globalpayments-api 3.10.13 → 3.10.15
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/CHANGELOG.md +11 -1
- package/lib/src/Builders/RequestBuilder/GpApi/GpApiAuthorizationRequestBuilder.js +21 -0
- package/lib/src/Builders/RequestBuilder/GpApi/GpApiAuthorizationRequestBuilder.js.map +1 -1
- package/lib/src/Builders/RequestBuilder/GpApi/GpApiSessionInfo.d.ts +11 -2
- package/lib/src/Builders/RequestBuilder/GpApi/GpApiSessionInfo.js +44 -5
- package/lib/src/Builders/RequestBuilder/GpApi/GpApiSessionInfo.js.map +1 -1
- package/lib/src/Entities/GpApi/PorticoTokenConfig.d.ts +25 -0
- package/lib/src/Entities/GpApi/PorticoTokenConfig.js +30 -0
- package/lib/src/Entities/GpApi/PorticoTokenConfig.js.map +1 -0
- package/lib/src/Entities/GpApi/index.d.ts +1 -0
- package/lib/src/Entities/GpApi/index.js +1 -0
- package/lib/src/Entities/GpApi/index.js.map +1 -1
- package/lib/src/Entities/Transaction.d.ts +2 -0
- package/lib/src/Entities/Transaction.js +2 -0
- package/lib/src/Entities/Transaction.js.map +1 -1
- package/lib/src/Entities/TransactionSummary.d.ts +1 -0
- package/lib/src/Entities/TransactionSummary.js +1 -0
- package/lib/src/Entities/TransactionSummary.js.map +1 -1
- package/lib/src/Entities/UPA/ExtraChargeType.d.ts +8 -0
- package/lib/src/Entities/UPA/ExtraChargeType.js +13 -0
- package/lib/src/Entities/UPA/ExtraChargeType.js.map +1 -0
- package/lib/src/Entities/UPA/Lodging.d.ts +11 -0
- package/lib/src/Entities/UPA/Lodging.js +15 -0
- package/lib/src/Entities/UPA/Lodging.js.map +1 -0
- package/lib/src/Entities/UPA/POSData.d.ts +6 -0
- package/lib/src/Entities/UPA/POSData.js +11 -0
- package/lib/src/Entities/UPA/POSData.js.map +1 -0
- package/lib/src/Gateways/GpApiConnector.d.ts +0 -6
- package/lib/src/Gateways/GpApiConnector.js +22 -43
- package/lib/src/Gateways/GpApiConnector.js.map +1 -1
- package/lib/src/Gateways/PorticoConnector.js +4 -6
- package/lib/src/Gateways/PorticoConnector.js.map +1 -1
- package/lib/src/Mapping/GpApiMapping.js +7 -0
- package/lib/src/Mapping/GpApiMapping.js.map +1 -1
- package/lib/src/ServiceConfigs/Gateways/GpApiConfig.d.ts +6 -0
- package/lib/src/ServiceConfigs/Gateways/GpApiConfig.js +25 -2
- package/lib/src/ServiceConfigs/Gateways/GpApiConfig.js.map +1 -1
- package/lib/src/Services/GpApiServices.js +4 -1
- package/lib/src/Services/GpApiServices.js.map +1 -1
- package/lib/src/Terminals/Builders/TerminalAuthBuilder.d.ts +1 -1
- package/lib/src/Terminals/Builders/TerminalAuthBuilder.js +11 -18
- package/lib/src/Terminals/Builders/TerminalAuthBuilder.js.map +1 -1
- package/lib/src/Terminals/Builders/TerminalManageBuilder.d.ts +1 -0
- package/lib/src/Terminals/Builders/TerminalManageBuilder.js +4 -0
- package/lib/src/Terminals/Builders/TerminalManageBuilder.js.map +1 -1
- package/lib/src/Terminals/Builders/TerminalReportBuilder.d.ts +15 -0
- package/lib/src/Terminals/Builders/TerminalReportBuilder.js +49 -0
- package/lib/src/Terminals/Builders/TerminalReportBuilder.js.map +1 -0
- package/lib/src/Terminals/UPA/Entities/UpaModels.d.ts +62 -0
- package/lib/src/Terminals/UPA/Entities/UpaModels.js +28 -0
- package/lib/src/Terminals/UPA/Entities/UpaModels.js.map +1 -0
- package/lib/src/Terminals/UPA/Entities/UpaSearchCriteria.d.ts +5 -0
- package/lib/src/Terminals/UPA/Entities/UpaSearchCriteria.js +10 -0
- package/lib/src/Terminals/UPA/Entities/UpaSearchCriteria.js.map +1 -0
- package/lib/src/Terminals/UPA/Reponses/BatchList.d.ts +16 -0
- package/lib/src/Terminals/UPA/Reponses/BatchList.js +82 -0
- package/lib/src/Terminals/UPA/Reponses/BatchList.js.map +1 -0
- package/lib/src/Terminals/UPA/Reponses/BatchReportResponse.d.ts +55 -0
- package/lib/src/Terminals/UPA/Reponses/BatchReportResponse.js +213 -0
- package/lib/src/Terminals/UPA/Reponses/BatchReportResponse.js.map +1 -0
- package/lib/src/Terminals/UPA/Reponses/OpenTabDetailsResponse.d.ts +25 -0
- package/lib/src/Terminals/UPA/Reponses/OpenTabDetailsResponse.js +109 -0
- package/lib/src/Terminals/UPA/Reponses/OpenTabDetailsResponse.js.map +1 -0
- package/lib/src/Terminals/UPA/Reponses/SafReportResponse.d.ts +36 -0
- package/lib/src/Terminals/UPA/Reponses/SafReportResponse.js +181 -0
- package/lib/src/Terminals/UPA/Reponses/SafReportResponse.js.map +1 -0
- package/lib/src/Terminals/UPA/Reponses/TransactionResponse.js +9 -2
- package/lib/src/Terminals/UPA/Reponses/TransactionResponse.js.map +1 -1
- package/lib/src/Terminals/UPA/Reponses/UpaEODResponse.d.ts +21 -0
- package/lib/src/Terminals/UPA/Reponses/UpaEODResponse.js +106 -0
- package/lib/src/Terminals/UPA/Reponses/UpaEODResponse.js.map +1 -0
- package/lib/src/Terminals/UPA/Reponses/UpaGiftCardResponse.d.ts +41 -0
- package/lib/src/Terminals/UPA/Reponses/UpaGiftCardResponse.js +93 -0
- package/lib/src/Terminals/UPA/Reponses/UpaGiftCardResponse.js.map +1 -0
- package/lib/src/Terminals/UPA/Reponses/UpaSAFResponse.d.ts +35 -0
- package/lib/src/Terminals/UPA/Reponses/UpaSAFResponse.js +194 -0
- package/lib/src/Terminals/UPA/Reponses/UpaSAFResponse.js.map +1 -0
- package/lib/src/Terminals/UPA/Reponses/UpaSignatureResponse.d.ts +18 -0
- package/lib/src/Terminals/UPA/Reponses/UpaSignatureResponse.js +94 -0
- package/lib/src/Terminals/UPA/Reponses/UpaSignatureResponse.js.map +1 -0
- package/lib/src/Terminals/UPA/UpaController.js +4 -1
- package/lib/src/Terminals/UPA/UpaController.js.map +1 -1
- package/lib/src/Utils/SdkVersion.d.ts +1 -0
- package/lib/src/Utils/SdkVersion.js +48 -0
- package/lib/src/Utils/SdkVersion.js.map +1 -0
- package/lib/src/Utils/index.d.ts +1 -0
- package/lib/src/Utils/index.js +1 -0
- package/lib/src/Utils/index.js.map +1 -1
- package/lib/test/Integration/Gateways/CI/gpapi/GpApiTransactionsTests.test.js +69 -0
- package/lib/test/Integration/Gateways/CI/gpapi/GpApiTransactionsTests.test.js.map +1 -0
- package/lib/test/Integration/Gateways/CI/portico/PorticoCreditTests.test.js +111 -0
- package/lib/test/Integration/Gateways/CI/portico/PorticoCreditTests.test.js.map +1 -0
- package/lib/test/Integration/Gateways/CI/upa_mitc/UpaFunctionalityTests.test.js +84 -0
- package/lib/test/Integration/Gateways/CI/upa_mitc/UpaFunctionalityTests.test.js.map +1 -0
- package/lib/test/Integration/Gateways/GpApiConnector/AccessTokenPorticoCredentials.test.d.ts +1 -0
- package/lib/test/Integration/Gateways/GpApiConnector/AccessTokenPorticoCredentials.test.js +175 -0
- package/lib/test/Integration/Gateways/GpApiConnector/AccessTokenPorticoCredentials.test.js.map +1 -0
- package/lib/test/Integration/Gateways/GpApiConnector/GpApiCreateTokenWithPorticoCredentialTests.test.d.ts +1 -0
- package/lib/test/Integration/Gateways/GpApiConnector/GpApiCreateTokenWithPorticoCredentialTests.test.js +205 -0
- package/lib/test/Integration/Gateways/GpApiConnector/GpApiCreateTokenWithPorticoCredentialTests.test.js.map +1 -0
- package/lib/test/Integration/Gateways/GpApiConnector/VisaAft.test.d.ts +1 -0
- package/lib/test/Integration/Gateways/GpApiConnector/VisaAft.test.js +168 -0
- package/lib/test/Integration/Gateways/GpApiConnector/VisaAft.test.js.map +1 -0
- package/lib/test/Integration/Gateways/PorticoConnector/GlobalTransactionId.test.d.ts +1 -0
- package/lib/test/Integration/Gateways/PorticoConnector/GlobalTransactionId.test.js +243 -0
- package/lib/test/Integration/Gateways/PorticoConnector/GlobalTransactionId.test.js.map +1 -0
- package/lib/test/Unit/Builders/AuthorizationBuilder/SupplementaryData.test.d.ts +1 -0
- package/lib/test/Unit/Builders/AuthorizationBuilder/SupplementaryData.test.js +147 -0
- package/lib/test/Unit/Builders/AuthorizationBuilder/SupplementaryData.test.js.map +1 -0
- package/lib/test/Unit/Terminals/UPA/UpaStory1Methods.test.d.ts +1 -0
- package/lib/test/Unit/Terminals/UPA/UpaStory1Methods.test.js +250 -0
- package/lib/test/Unit/Terminals/UPA/UpaStory1Methods.test.js.map +1 -0
- package/lib/test/Unit/Terminals/UPA/UpaStory2Methods.test.d.ts +1 -0
- package/lib/test/Unit/Terminals/UPA/UpaStory2Methods.test.js +1277 -0
- package/lib/test/Unit/Terminals/UPA/UpaStory2Methods.test.js.map +1 -0
- package/lib/test/Unit/Terminals/UPA/UpaStory3_4Methods.test.d.ts +1 -0
- package/lib/test/Unit/Terminals/UPA/UpaStory3_4Methods.test.js +411 -0
- package/lib/test/Unit/Terminals/UPA/UpaStory3_4Methods.test.js.map +1 -0
- package/lib/test/Utils/CiTestingHarness.d.ts +21 -0
- package/lib/test/Utils/CiTestingHarness.js +65 -7
- package/lib/test/Utils/CiTestingHarness.js.map +1 -1
- package/package.json +1 -1
- package/lib/test/Integration/Gateways/CI/GpApiCreditCardNotPresentTests.test.js +0 -90
- package/lib/test/Integration/Gateways/CI/GpApiCreditCardNotPresentTests.test.js.map +0 -1
- package/lib/test/Integration/Gateways/CI/PorticoCreditTests.test.js +0 -63
- package/lib/test/Integration/Gateways/CI/PorticoCreditTests.test.js.map +0 -1
- package/lib/test/Integration/Gateways/CI/UpaMicTests.test.js +0 -52
- package/lib/test/Integration/Gateways/CI/UpaMicTests.test.js.map +0 -1
- /package/lib/test/Integration/Gateways/CI/{GpApiCreditCardNotPresentTests.test.d.ts → gpapi/GpApiTransactionsTests.test.d.ts} +0 -0
- /package/lib/test/Integration/Gateways/CI/{PorticoCreditTests.test.d.ts → portico/PorticoCreditTests.test.d.ts} +0 -0
- /package/lib/test/Integration/Gateways/CI/{UpaMicTests.test.d.ts → upa_mitc/UpaFunctionalityTests.test.d.ts} +0 -0
|
@@ -0,0 +1,1277 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
/**
|
|
4
|
+
* Unit tests for UPA Story 2 methods:
|
|
5
|
+
* balance(), reverse(), deletePreAuth(), startCardTransaction(), reboot()
|
|
6
|
+
*
|
|
7
|
+
* Balance – UpaEbtTests.cs:EbtFoodstampBalanceInquiry, EbtCashBenefitsBalanceInquiry, EbtBalance
|
|
8
|
+
* Reverse – UpaCreditTests.cs:CreditSale_WhenReversedByTerminalRefNumber_ShouldReturnSuccess
|
|
9
|
+
* DeletePreAuth – UpaCreditTests.cs:DeletePreAuth / UpaMicTests.cs:CreditDeletePreAuth
|
|
10
|
+
* StartCardTransaction – UpaAdminTests.cs (4 test cases)
|
|
11
|
+
* Reboot – UpaAdminTests.cs:Reboot / UpaMicTests.cs:Reboot
|
|
12
|
+
*/
|
|
13
|
+
const src_1 = require("../../../../src");
|
|
14
|
+
const Logging_1 = require("../../../../src/Utils/Logging");
|
|
15
|
+
const DeviceService_1 = require("../../../../src/Services/DeviceService");
|
|
16
|
+
const Enums_1 = require("../../../../src/Terminals/Enums");
|
|
17
|
+
const TransactionResponse_1 = require("../../../../src/Terminals/UPA/Reponses/TransactionResponse");
|
|
18
|
+
const UpaGiftCardResponse_1 = require("../../../../src/Terminals/UPA/Reponses/UpaGiftCardResponse");
|
|
19
|
+
const AcquisitionType_1 = require("../../../../src/Entities/Enums/AcquisitionType");
|
|
20
|
+
const CardTypeFilter_1 = require("../../../../src/Entities/Enums/CardTypeFilter");
|
|
21
|
+
const ProcessIndicator_1 = require("../../../../src/Entities/UPA/ProcessIndicator");
|
|
22
|
+
const UpaParam_1 = require("../../../../src/Entities/UPA/UpaParam");
|
|
23
|
+
const UpaTransactionData_1 = require("../../../../src/Entities/UPA/UpaTransactionData");
|
|
24
|
+
const Enums_2 = require("../../../../src/Entities/Enums");
|
|
25
|
+
const useLiveMic = process.env.UPA_LIVE === "true";
|
|
26
|
+
const gpApiAppId = process.env.GP_API_APP_ID;
|
|
27
|
+
const gpApiAppKey = process.env.GP_API_APP_KEY;
|
|
28
|
+
const hasLiveGpApiCredentials = !!gpApiAppId && !!gpApiAppKey;
|
|
29
|
+
const describeUpaStory2 = useLiveMic && !hasLiveGpApiCredentials ? describe.skip : describe;
|
|
30
|
+
const liveOnlyStory2 = useLiveMic ? test : test.skip;
|
|
31
|
+
jest.setTimeout(240000);
|
|
32
|
+
/* eslint-disable indent */
|
|
33
|
+
function expectLiveSuccess(response, expectedCommand) {
|
|
34
|
+
const expectedCommands = Array.isArray(expectedCommand)
|
|
35
|
+
? expectedCommand
|
|
36
|
+
: [expectedCommand];
|
|
37
|
+
expect(expectedCommands).toContain(response.command);
|
|
38
|
+
expect(response.status).toBe("Success");
|
|
39
|
+
expect(response.deviceResponseCode).toBe("00");
|
|
40
|
+
}
|
|
41
|
+
function formatLiveFailure(response, operation) {
|
|
42
|
+
const deviceCode = response.deviceResponseCode ?? "";
|
|
43
|
+
const hostCode = response.responseCode ?? "";
|
|
44
|
+
return `${operation} prerequisite failed in live MIC: device ${deviceCode} ${response.deviceResponseMessage ?? ""}; host ${hostCode} ${response.responseText ?? ""}`.trim();
|
|
45
|
+
}
|
|
46
|
+
function isKnownLiveSaleBlocker(response) {
|
|
47
|
+
const pinVerificationError = response.deviceResponseCode === "HOST001" &&
|
|
48
|
+
response.responseCode === "86" &&
|
|
49
|
+
response.responseText === "CANT VERIFY PIN";
|
|
50
|
+
const timeoutError = response.deviceResponseCode === "APP002" &&
|
|
51
|
+
response.deviceResponseMessage === "TIMEOUT";
|
|
52
|
+
return pinVerificationError || timeoutError;
|
|
53
|
+
}
|
|
54
|
+
function isKnownLiveBalanceBlocker(response) {
|
|
55
|
+
const pinVerificationError = response.deviceResponseCode === "HOST001" &&
|
|
56
|
+
response.responseCode === "86" &&
|
|
57
|
+
response.responseText === "CANT VERIFY PIN";
|
|
58
|
+
const hostCommunicationError = response.deviceResponseCode === "HOST002" &&
|
|
59
|
+
response.deviceResponseMessage === "HOST COMMUNICATIONS ERROR";
|
|
60
|
+
const userCancelledError = response.deviceResponseCode === "APP001" &&
|
|
61
|
+
response.deviceResponseMessage === "TRANSACTION CANCELLED BY USER";
|
|
62
|
+
const timeoutError = response.deviceResponseCode === "APP002" &&
|
|
63
|
+
response.deviceResponseMessage === "TIMEOUT";
|
|
64
|
+
return (pinVerificationError ||
|
|
65
|
+
hostCommunicationError ||
|
|
66
|
+
userCancelledError ||
|
|
67
|
+
timeoutError);
|
|
68
|
+
}
|
|
69
|
+
function isKnownLiveBusyBlocker(response) {
|
|
70
|
+
return (response.command === "SendCommand" &&
|
|
71
|
+
response.deviceResponseCode === "32" &&
|
|
72
|
+
response.deviceResponseMessage === "BUSY");
|
|
73
|
+
}
|
|
74
|
+
function isKnownLiveStartCardTransactionBlocker(response) {
|
|
75
|
+
const documentedErrorCodes = [
|
|
76
|
+
"CARD002",
|
|
77
|
+
"CARD003",
|
|
78
|
+
"CARD004",
|
|
79
|
+
"CARD006",
|
|
80
|
+
"CARD007",
|
|
81
|
+
"CARD009",
|
|
82
|
+
"CARD011",
|
|
83
|
+
"CARD018",
|
|
84
|
+
"APP001",
|
|
85
|
+
"APP002",
|
|
86
|
+
"APP013",
|
|
87
|
+
"ERR013",
|
|
88
|
+
];
|
|
89
|
+
return (!!response.deviceResponseCode &&
|
|
90
|
+
documentedErrorCodes.includes(response.deviceResponseCode));
|
|
91
|
+
}
|
|
92
|
+
function isKnownLiveGiftCardBlocker(response) {
|
|
93
|
+
return (response.deviceResponseCode === "GIFT001" &&
|
|
94
|
+
response.deviceResponseMessage === "NOT A VALID GIFT CARD");
|
|
95
|
+
}
|
|
96
|
+
function isKnownLiveReverseAutoFallbackBlocker(response) {
|
|
97
|
+
return (response.command === "Reversal" &&
|
|
98
|
+
response.deviceResponseCode === "ERR013" &&
|
|
99
|
+
response.deviceResponseMessage === "[tranNo]-MISSING MANDATORY FIELD");
|
|
100
|
+
}
|
|
101
|
+
function isKnownLiveTransportTimeout(error) {
|
|
102
|
+
return (error instanceof Error &&
|
|
103
|
+
(error.message === "Socket timeout occurred." ||
|
|
104
|
+
error.message.includes("ECONNRESET") ||
|
|
105
|
+
error.message.includes("socket hang up")));
|
|
106
|
+
}
|
|
107
|
+
function expectParsedStartCardTransactionResponse(response) {
|
|
108
|
+
expect(response.command).toBe("StartCardTransaction");
|
|
109
|
+
expect(response.status).toBe("Success");
|
|
110
|
+
expect(response.deviceResponseCode).toBe("00");
|
|
111
|
+
if (response.acquisitionType) {
|
|
112
|
+
expect(response.acquisitionType).toMatch(/^(INSERT|CONTACT|CONTACTLESS|SWIPE|MANUAL|SCAN|TAP)$/);
|
|
113
|
+
}
|
|
114
|
+
if (response.luhnCheckPassed) {
|
|
115
|
+
expect(response.luhnCheckPassed).toMatch(/^[YN]$/);
|
|
116
|
+
}
|
|
117
|
+
if (response.fallback) {
|
|
118
|
+
expect(response.fallback).toMatch(/^[01]$/);
|
|
119
|
+
}
|
|
120
|
+
if (response.avsFlag) {
|
|
121
|
+
expect(response.avsFlag).toMatch(/^[01]$/);
|
|
122
|
+
}
|
|
123
|
+
if (response.cardSecurityPromptFlag) {
|
|
124
|
+
expect(response.cardSecurityPromptFlag).toMatch(/^[01]$/);
|
|
125
|
+
}
|
|
126
|
+
if (response.cashBackFlag) {
|
|
127
|
+
expect(response.cashBackFlag).toMatch(/^[01]$/);
|
|
128
|
+
}
|
|
129
|
+
if (response.surchargeFlag) {
|
|
130
|
+
expect(response.surchargeFlag).toMatch(/^[01]$/);
|
|
131
|
+
}
|
|
132
|
+
if (response.dccEligible) {
|
|
133
|
+
expect(response.dccEligible).toMatch(/^[01]$/);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
function delay(ms) {
|
|
137
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
138
|
+
}
|
|
139
|
+
async function expectLiveDeletePreAuthFailure(action, operation) {
|
|
140
|
+
try {
|
|
141
|
+
const response = await action();
|
|
142
|
+
expect(response).not.toBeNull();
|
|
143
|
+
expect(response).toBeInstanceOf(TransactionResponse_1.TransactionResponse);
|
|
144
|
+
if (isKnownLiveBusyBlocker(response)) {
|
|
145
|
+
console.warn(formatLiveFailure(response, operation));
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
expect(response.status !== "Success" ||
|
|
149
|
+
response.deviceResponseCode !== "00" ||
|
|
150
|
+
(!!response.responseCode && response.responseCode !== "00")).toBe(true);
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
if (isKnownLiveTransportTimeout(error)) {
|
|
154
|
+
console.warn(`${operation} timed out while waiting on the device or gateway.`);
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
expect(error).toBeInstanceOf(Error);
|
|
158
|
+
expect(error.message).toBeTruthy();
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
function expectLiveBalanceResponseFields(response) {
|
|
162
|
+
expect(["BalanceInquiry", "SendCommand"]).toContain(response.command);
|
|
163
|
+
expect(response.status).toBe("Success");
|
|
164
|
+
expect(response.deviceResponseCode).toBe("00");
|
|
165
|
+
expect(response.responseCode).toBe("00");
|
|
166
|
+
expect(response.responseText).toBeTruthy();
|
|
167
|
+
if (response.referenceNumber) {
|
|
168
|
+
expect(response.referenceNumber).toMatch(/^[A-Z0-9]+$/i);
|
|
169
|
+
}
|
|
170
|
+
expect(response.availableBalance).not.toBeUndefined();
|
|
171
|
+
if (response.transactionType) {
|
|
172
|
+
expect(response.transactionType).toContain("BALANCE");
|
|
173
|
+
}
|
|
174
|
+
if (response.maskedCardNumber) {
|
|
175
|
+
expect(response.maskedCardNumber).toMatch(/\*{2,}|X{2,}/);
|
|
176
|
+
}
|
|
177
|
+
if (response.entryMethod) {
|
|
178
|
+
expect(response.entryMethod).toMatch(/^(MANUAL|SWIPE|INSERT|TAP|SCAN|NONE)$/);
|
|
179
|
+
}
|
|
180
|
+
if (response.expirationDate) {
|
|
181
|
+
expect(response.expirationDate).toMatch(/^\d{2}\/\d{2}$/);
|
|
182
|
+
}
|
|
183
|
+
if (response.pinVerified) {
|
|
184
|
+
expect(response.pinVerified).toMatch(/^[01]$/);
|
|
185
|
+
}
|
|
186
|
+
if (response.fallback) {
|
|
187
|
+
expect(response.fallback).toMatch(/^[01]$/);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
async function expectLiveBalanceFailure(action, operation) {
|
|
191
|
+
try {
|
|
192
|
+
const response = await action();
|
|
193
|
+
expect(response).not.toBeNull();
|
|
194
|
+
expect(response).toBeInstanceOf(TransactionResponse_1.TransactionResponse);
|
|
195
|
+
if (isKnownLiveBusyBlocker(response)) {
|
|
196
|
+
console.warn(formatLiveFailure(response, operation));
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
expect(response.status !== "Success" ||
|
|
200
|
+
response.deviceResponseCode !== "00" ||
|
|
201
|
+
(!!response.responseCode && response.responseCode !== "00")).toBe(true);
|
|
202
|
+
}
|
|
203
|
+
catch (error) {
|
|
204
|
+
if (isKnownLiveTransportTimeout(error)) {
|
|
205
|
+
console.warn(`${operation} timed out while waiting on the device or gateway.`);
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
expect(error).toBeInstanceOf(Error);
|
|
209
|
+
expect(error.message).toBeTruthy();
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
async function reverseLiveSaleWithRetry(device, terminalRefNumber, amount, maxAttempts = 3) {
|
|
213
|
+
let response;
|
|
214
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
|
215
|
+
const builder = device.reverse().withEcrId(12);
|
|
216
|
+
if (terminalRefNumber) {
|
|
217
|
+
builder.withTerminalRefNumber(terminalRefNumber);
|
|
218
|
+
}
|
|
219
|
+
if (amount !== undefined) {
|
|
220
|
+
builder.withAmount(amount);
|
|
221
|
+
}
|
|
222
|
+
response = await builder.execute();
|
|
223
|
+
if (!isKnownLiveBusyBlocker(response) || attempt === maxAttempts) {
|
|
224
|
+
return response;
|
|
225
|
+
}
|
|
226
|
+
await delay(10000);
|
|
227
|
+
}
|
|
228
|
+
return response;
|
|
229
|
+
}
|
|
230
|
+
function expectLiveReverseResponseFields(response) {
|
|
231
|
+
expect(response.command).toBe("Reversal");
|
|
232
|
+
expect(response.status).toBe("Success");
|
|
233
|
+
expect(response.deviceResponseCode).toBe("00");
|
|
234
|
+
expect(response.responseCode).toBe("00");
|
|
235
|
+
expect(response.responseText).toBeTruthy();
|
|
236
|
+
expect(response.terminalRefNumber).toBeTruthy();
|
|
237
|
+
if (response.referenceNumber) {
|
|
238
|
+
expect(response.referenceNumber).toMatch(/^[A-Z0-9]+$/i);
|
|
239
|
+
}
|
|
240
|
+
if (response.transactionType) {
|
|
241
|
+
expect(response.transactionType).toContain("REVERSAL");
|
|
242
|
+
}
|
|
243
|
+
if (response.maskedCardNumber) {
|
|
244
|
+
expect(response.maskedCardNumber).toMatch(/\*{2,}|X{2,}/);
|
|
245
|
+
}
|
|
246
|
+
if (response.entryMethod) {
|
|
247
|
+
expect(response.entryMethod).toMatch(/^(MANUAL|SWIPE|INSERT|TAP|SCAN|NONE)$/);
|
|
248
|
+
}
|
|
249
|
+
if (response.expirationDate) {
|
|
250
|
+
expect(response.expirationDate).toMatch(/^\d{2}\/\d{2}$/);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
async function expectLiveReverseFailure(action, operation) {
|
|
254
|
+
try {
|
|
255
|
+
const response = await action();
|
|
256
|
+
expect(response).not.toBeNull();
|
|
257
|
+
expect(response).toBeInstanceOf(TransactionResponse_1.TransactionResponse);
|
|
258
|
+
if (isKnownLiveBusyBlocker(response)) {
|
|
259
|
+
console.warn(formatLiveFailure(response, operation));
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
expect(response.status !== "Success" ||
|
|
263
|
+
response.deviceResponseCode !== "00" ||
|
|
264
|
+
(!!response.responseCode && response.responseCode !== "00")).toBe(true);
|
|
265
|
+
}
|
|
266
|
+
catch (error) {
|
|
267
|
+
if (isKnownLiveTransportTimeout(error)) {
|
|
268
|
+
console.warn(`${operation} timed out while waiting on the device or gateway.`);
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
expect(error).toBeInstanceOf(Error);
|
|
272
|
+
expect(error.message).toBeTruthy();
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
async function deletePreAuthWithRetry(device, transactionId, amount, maxAttempts = 3) {
|
|
276
|
+
let response;
|
|
277
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
|
278
|
+
response = await device
|
|
279
|
+
.deletePreAuth()
|
|
280
|
+
.withEcrId(13)
|
|
281
|
+
.withTransactionId(transactionId)
|
|
282
|
+
.withAmount(amount)
|
|
283
|
+
.execute();
|
|
284
|
+
if (!isKnownLiveBusyBlocker(response) || attempt === maxAttempts) {
|
|
285
|
+
return response;
|
|
286
|
+
}
|
|
287
|
+
await delay(10000);
|
|
288
|
+
}
|
|
289
|
+
return response;
|
|
290
|
+
}
|
|
291
|
+
async function createLiveSale(device) {
|
|
292
|
+
const response = await device
|
|
293
|
+
.sale(1.0)
|
|
294
|
+
.withGratuity(0)
|
|
295
|
+
.withEcrId(13)
|
|
296
|
+
.withClerkId(123)
|
|
297
|
+
.execute();
|
|
298
|
+
expect(response).toBeInstanceOf(TransactionResponse_1.TransactionResponse);
|
|
299
|
+
if (response.deviceResponseCode === "00") {
|
|
300
|
+
expect(["COMPLETE", "INITIATED"]).toContain(response.deviceResponseText);
|
|
301
|
+
expect(response.terminalRefNumber).toBeTruthy();
|
|
302
|
+
}
|
|
303
|
+
return response;
|
|
304
|
+
}
|
|
305
|
+
async function createLiveDebitSale(device) {
|
|
306
|
+
const response = await device
|
|
307
|
+
.sale(1.0)
|
|
308
|
+
.withPaymentMethodType(src_1.PaymentMethodType.Debit)
|
|
309
|
+
.withCashBack(0)
|
|
310
|
+
.withEcrId(13)
|
|
311
|
+
.withClerkId(123)
|
|
312
|
+
.execute();
|
|
313
|
+
expect(response).toBeInstanceOf(TransactionResponse_1.TransactionResponse);
|
|
314
|
+
if (response.deviceResponseCode === "00") {
|
|
315
|
+
expect(["COMPLETE", "INITIATED"]).toContain(response.deviceResponseText);
|
|
316
|
+
expect(response.terminalRefNumber).toBeTruthy();
|
|
317
|
+
}
|
|
318
|
+
return response;
|
|
319
|
+
}
|
|
320
|
+
async function createLivePreAuth(device) {
|
|
321
|
+
const response = await device
|
|
322
|
+
.authorize(1.0)
|
|
323
|
+
.withEcrId(13)
|
|
324
|
+
.withClerkId(123)
|
|
325
|
+
.execute();
|
|
326
|
+
expect(response).toBeInstanceOf(TransactionResponse_1.TransactionResponse);
|
|
327
|
+
if (response.deviceResponseCode !== "00") {
|
|
328
|
+
throw new Error(formatLiveFailure(response, "PreAuth"));
|
|
329
|
+
}
|
|
330
|
+
expect(["COMPLETE", "INITIATED"]).toContain(response.deviceResponseText);
|
|
331
|
+
expect(response.transactionId).toBeTruthy();
|
|
332
|
+
return response;
|
|
333
|
+
}
|
|
334
|
+
async function executeLiveStartCardTransaction(device, param, indicator, transData, operation) {
|
|
335
|
+
let response;
|
|
336
|
+
try {
|
|
337
|
+
response = await device.startCardTransaction(param, indicator, transData);
|
|
338
|
+
}
|
|
339
|
+
catch (error) {
|
|
340
|
+
if (isKnownLiveTransportTimeout(error)) {
|
|
341
|
+
console.warn(`${operation} timed out while waiting on the device or gateway.`);
|
|
342
|
+
return undefined;
|
|
343
|
+
}
|
|
344
|
+
throw error;
|
|
345
|
+
}
|
|
346
|
+
expect(response).not.toBeNull();
|
|
347
|
+
expect(response).toBeInstanceOf(UpaGiftCardResponse_1.UpaGiftCardResponse);
|
|
348
|
+
if (isKnownLiveGiftCardBlocker(response) ||
|
|
349
|
+
isKnownLiveStartCardTransactionBlocker(response)) {
|
|
350
|
+
console.warn(formatLiveFailure(response, operation));
|
|
351
|
+
return undefined;
|
|
352
|
+
}
|
|
353
|
+
expectLiveSuccess(response, "StartCardTransaction");
|
|
354
|
+
expectParsedStartCardTransactionResponse(response);
|
|
355
|
+
return response;
|
|
356
|
+
}
|
|
357
|
+
/* eslint-enable indent */
|
|
358
|
+
// ===========================================================================
|
|
359
|
+
// Test infrastructure helpers
|
|
360
|
+
// ===========================================================================
|
|
361
|
+
function buildConfig(gpApiOverrides = {}) {
|
|
362
|
+
const config = new src_1.ConnectionConfig();
|
|
363
|
+
config.deviceType = src_1.DeviceType.UPA_DEVICE;
|
|
364
|
+
config.connectionMode = Enums_1.ConnectionModes.MEET_IN_THE_CLOUD;
|
|
365
|
+
config.requestIdProvider = { getRequestId: () => 9999 };
|
|
366
|
+
const logger = new Logging_1.SampleRequestLogger(new Logging_1.Logger("logs"));
|
|
367
|
+
config.requestLogger = logger;
|
|
368
|
+
if (useLiveMic && !hasLiveGpApiCredentials) {
|
|
369
|
+
throw new Error("Set GP_API_APP_ID and GP_API_APP_KEY to run live UPA Story 2 tests.");
|
|
370
|
+
}
|
|
371
|
+
const gpApiConfig = new src_1.GpApiConfig();
|
|
372
|
+
gpApiConfig.appId = gpApiAppId ?? "UNIT_TEST_APP_ID";
|
|
373
|
+
gpApiConfig.appKey = gpApiAppKey ?? "UNIT_TEST_APP_KEY";
|
|
374
|
+
gpApiConfig.environment = src_1.Environment.Test;
|
|
375
|
+
gpApiConfig.channel = src_1.Channel.CardPresent;
|
|
376
|
+
gpApiConfig.country = "US";
|
|
377
|
+
gpApiConfig.deviceCurrency = "USD";
|
|
378
|
+
gpApiConfig.requestLogger = logger;
|
|
379
|
+
if (useLiveMic) {
|
|
380
|
+
gpApiConfig.accessTokenInfo = new src_1.AccessTokenInfo();
|
|
381
|
+
}
|
|
382
|
+
else {
|
|
383
|
+
gpApiConfig.accessTokenInfo = {
|
|
384
|
+
transactionProcessingAccountName: "test",
|
|
385
|
+
accessToken: "UNIT_TEST_FAKE_TOKEN",
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
Object.assign(gpApiConfig, gpApiOverrides);
|
|
389
|
+
config.gatewayConfig = gpApiConfig;
|
|
390
|
+
return config;
|
|
391
|
+
}
|
|
392
|
+
// ===========================================================================
|
|
393
|
+
// balance()
|
|
394
|
+
// References:
|
|
395
|
+
// UpaEbtTests.cs – EbtFoodstampBalanceInquiry, EbtCashBenefitsBalanceInquiry, EbtBalance
|
|
396
|
+
// Assert.AreEqual("00", response.ResponseCode / DeviceResponseCode)
|
|
397
|
+
// Assert.AreEqual("Success", response.DeviceResponseText)
|
|
398
|
+
// ===========================================================================
|
|
399
|
+
describeUpaStory2("UPA Story 2 – balance()", () => {
|
|
400
|
+
let device;
|
|
401
|
+
beforeEach(() => {
|
|
402
|
+
device = DeviceService_1.DeviceService.create(buildConfig());
|
|
403
|
+
device.ecrId = "13";
|
|
404
|
+
});
|
|
405
|
+
/**
|
|
406
|
+
* Mirrors UpaEbtTests.cs – EbtFoodstampBalanceInquiry
|
|
407
|
+
* var response = _device.Balance().WithEcrId(13)
|
|
408
|
+
* .WithPaymentMethodType(PaymentMethodType.EBT)
|
|
409
|
+
* .WithCurrency(CurrencyType.FOODSTAMPS).Execute();
|
|
410
|
+
* Assert.AreEqual("00", response.ResponseCode);
|
|
411
|
+
*/
|
|
412
|
+
test("[UpaEbtTests] balance() with EBT Foodstamp returns deviceResponseCode == '00'", async () => {
|
|
413
|
+
const response = await device
|
|
414
|
+
.balance()
|
|
415
|
+
.withEcrId(13)
|
|
416
|
+
.withPaymentMethodType(src_1.PaymentMethodType.EBT)
|
|
417
|
+
.execute();
|
|
418
|
+
expect(response).not.toBeNull();
|
|
419
|
+
expect(response).toBeInstanceOf(TransactionResponse_1.TransactionResponse);
|
|
420
|
+
if (useLiveMic) {
|
|
421
|
+
if (isKnownLiveBalanceBlocker(response)) {
|
|
422
|
+
console.warn(formatLiveFailure(response, "BalanceInquiry Foodstamp"));
|
|
423
|
+
return;
|
|
424
|
+
}
|
|
425
|
+
if (isKnownLiveBusyBlocker(response)) {
|
|
426
|
+
console.warn(formatLiveFailure(response, "BalanceInquiry Foodstamp"));
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
expectLiveSuccess(response, ["BalanceInquiry", "SendCommand"]);
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
expect(response.deviceResponseCode).toBe("00");
|
|
433
|
+
});
|
|
434
|
+
/**
|
|
435
|
+
* Mirrors UpaEbtTests.cs – EbtBalance
|
|
436
|
+
* Assert.AreEqual("Success", response.DeviceResponseText);
|
|
437
|
+
* Assert.AreEqual("00", response.DeviceResponseCode);
|
|
438
|
+
*/
|
|
439
|
+
test("[UpaEbtTests] balance() with EBT returns status Success and deviceResponseCode '00'", async () => {
|
|
440
|
+
const response = await device
|
|
441
|
+
.balance()
|
|
442
|
+
.withEcrId(13)
|
|
443
|
+
.withPaymentMethodType(src_1.PaymentMethodType.EBT)
|
|
444
|
+
.execute();
|
|
445
|
+
expect(response).not.toBeNull();
|
|
446
|
+
if (useLiveMic) {
|
|
447
|
+
if (isKnownLiveBalanceBlocker(response)) {
|
|
448
|
+
console.warn(formatLiveFailure(response, "BalanceInquiry EBT"));
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
if (isKnownLiveBusyBlocker(response)) {
|
|
452
|
+
console.warn(formatLiveFailure(response, "BalanceInquiry EBT"));
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
expectLiveSuccess(response, ["BalanceInquiry", "SendCommand"]);
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
expect(response.status).toBe("Success");
|
|
459
|
+
expect(response.deviceResponseText).toBe("Success");
|
|
460
|
+
expect(response.deviceResponseCode).toBe("00");
|
|
461
|
+
});
|
|
462
|
+
liveOnlyStory2("[LivePositive] balance() with MC card returns success", async () => {
|
|
463
|
+
const response = await device
|
|
464
|
+
.balance()
|
|
465
|
+
.withEcrId(13)
|
|
466
|
+
.withPaymentMethodType(src_1.PaymentMethodType.Credit)
|
|
467
|
+
.execute();
|
|
468
|
+
expect(response).not.toBeNull();
|
|
469
|
+
expect(response).toBeInstanceOf(TransactionResponse_1.TransactionResponse);
|
|
470
|
+
if (isKnownLiveBalanceBlocker(response)) {
|
|
471
|
+
console.warn(formatLiveFailure(response, "BalanceInquiry Mastercard"));
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
if (isKnownLiveBusyBlocker(response)) {
|
|
475
|
+
console.warn(formatLiveFailure(response, "BalanceInquiry Mastercard"));
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
expectLiveSuccess(response, ["BalanceInquiry", "SendCommand"]);
|
|
479
|
+
expectLiveBalanceResponseFields(response);
|
|
480
|
+
expect(response.cardGroup).toBe("CREDIT");
|
|
481
|
+
expect(response.cardType).toMatch(/^(MASTERCARD|MasterCard|MC)$/i);
|
|
482
|
+
});
|
|
483
|
+
liveOnlyStory2("[LivePositive] balance() returns documented response fields on success", async () => {
|
|
484
|
+
const response = await device
|
|
485
|
+
.balance()
|
|
486
|
+
.withEcrId(13)
|
|
487
|
+
.withPaymentMethodType(src_1.PaymentMethodType.Credit)
|
|
488
|
+
.execute();
|
|
489
|
+
expect(response).not.toBeNull();
|
|
490
|
+
expect(response).toBeInstanceOf(TransactionResponse_1.TransactionResponse);
|
|
491
|
+
if (isKnownLiveBalanceBlocker(response)) {
|
|
492
|
+
console.warn(formatLiveFailure(response, "BalanceInquiry response fields"));
|
|
493
|
+
return;
|
|
494
|
+
}
|
|
495
|
+
if (isKnownLiveBusyBlocker(response)) {
|
|
496
|
+
console.warn(formatLiveFailure(response, "BalanceInquiry response fields"));
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
expectLiveSuccess(response, ["BalanceInquiry", "SendCommand"]);
|
|
500
|
+
expectLiveBalanceResponseFields(response);
|
|
501
|
+
expect(response.cardType).toBeTruthy();
|
|
502
|
+
expect(response.cardGroup).toBeTruthy();
|
|
503
|
+
expect(response.cardHolderName).toBeTruthy();
|
|
504
|
+
});
|
|
505
|
+
liveOnlyStory2("[LivePositive] balance() with EBT populates ebtType and cardGroup", async () => {
|
|
506
|
+
const response = await device
|
|
507
|
+
.balance()
|
|
508
|
+
.withEcrId(13)
|
|
509
|
+
.withPaymentMethodType(src_1.PaymentMethodType.EBT)
|
|
510
|
+
.execute();
|
|
511
|
+
expect(response).not.toBeNull();
|
|
512
|
+
expect(response).toBeInstanceOf(TransactionResponse_1.TransactionResponse);
|
|
513
|
+
expect(["BalanceInquiry", "SendCommand"]).toContain(response.command);
|
|
514
|
+
if (isKnownLiveBusyBlocker(response)) {
|
|
515
|
+
console.warn(formatLiveFailure(response, "BalanceInquiry EBT field validation"));
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
518
|
+
if (isKnownLiveBalanceBlocker(response)) {
|
|
519
|
+
expect(response.cardGroup).toBeTruthy();
|
|
520
|
+
expect(response.ebtType).toBeTruthy();
|
|
521
|
+
expect(response.cardType).toBeTruthy();
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
expectLiveSuccess(response, ["BalanceInquiry", "SendCommand"]);
|
|
525
|
+
expectLiveBalanceResponseFields(response);
|
|
526
|
+
if (response.cardGroup !== "EBT" || !response.ebtType) {
|
|
527
|
+
console.warn("BalanceInquiry EBT field validation requires an actual EBT-presented card; the current live run returned a non-EBT successful balance response.");
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
expect(response.cardGroup).toBe("EBT");
|
|
531
|
+
expect(response.ebtType).toBeTruthy();
|
|
532
|
+
expect(response.cardType).toBeTruthy();
|
|
533
|
+
});
|
|
534
|
+
liveOnlyStory2("[LiveNegative] balance() with invalid target device surfaces device error", async () => {
|
|
535
|
+
const unavailableDevice = DeviceService_1.DeviceService.create(buildConfig());
|
|
536
|
+
unavailableDevice.ecrId = "99999999";
|
|
537
|
+
await expectLiveBalanceFailure(() => unavailableDevice
|
|
538
|
+
.balance()
|
|
539
|
+
.withEcrId(99999999)
|
|
540
|
+
.withPaymentMethodType(src_1.PaymentMethodType.Credit)
|
|
541
|
+
.execute(), "BalanceInquiry invalid target device");
|
|
542
|
+
});
|
|
543
|
+
liveOnlyStory2("[LiveSetup] balance() invalid clerk number documents current terminal behavior", async () => {
|
|
544
|
+
const response = await device
|
|
545
|
+
.balance()
|
|
546
|
+
.withEcrId(13)
|
|
547
|
+
.withClerkId(99999999)
|
|
548
|
+
.withPaymentMethodType(src_1.PaymentMethodType.Credit)
|
|
549
|
+
.execute();
|
|
550
|
+
expect(response).not.toBeNull();
|
|
551
|
+
expect(response).toBeInstanceOf(TransactionResponse_1.TransactionResponse);
|
|
552
|
+
if (isKnownLiveBusyBlocker(response)) {
|
|
553
|
+
console.warn(formatLiveFailure(response, "BalanceInquiry invalid clerk"));
|
|
554
|
+
return;
|
|
555
|
+
}
|
|
556
|
+
if (response.status !== "Success" ||
|
|
557
|
+
response.deviceResponseCode !== "00" ||
|
|
558
|
+
(!!response.responseCode && response.responseCode !== "00")) {
|
|
559
|
+
expect(response.deviceResponseCode).not.toBe("00");
|
|
560
|
+
return;
|
|
561
|
+
}
|
|
562
|
+
console.warn("BalanceInquiry invalid clerk number was accepted by the current terminal configuration.");
|
|
563
|
+
});
|
|
564
|
+
liveOnlyStory2("[LiveSetup] balance() host error omits availableBalance and documents current reference behavior", async () => {
|
|
565
|
+
const response = await device
|
|
566
|
+
.balance()
|
|
567
|
+
.withEcrId(13)
|
|
568
|
+
.withPaymentMethodType(src_1.PaymentMethodType.EBT)
|
|
569
|
+
.execute();
|
|
570
|
+
expect(response).not.toBeNull();
|
|
571
|
+
expect(response).toBeInstanceOf(TransactionResponse_1.TransactionResponse);
|
|
572
|
+
if (isKnownLiveBusyBlocker(response)) {
|
|
573
|
+
console.warn(formatLiveFailure(response, "BalanceInquiry host error"));
|
|
574
|
+
return;
|
|
575
|
+
}
|
|
576
|
+
if (response.deviceResponseCode === "HOST001") {
|
|
577
|
+
expect(response.availableBalance).toBeUndefined();
|
|
578
|
+
return;
|
|
579
|
+
}
|
|
580
|
+
if (response.deviceResponseCode === "APP002") {
|
|
581
|
+
console.warn(formatLiveFailure(response, "BalanceInquiry host error"));
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
584
|
+
console.warn("BalanceInquiry host error scenario was not reproduced in the current live run.");
|
|
585
|
+
});
|
|
586
|
+
test.skip("[EnvDependent] balance() forced transaction timeout requires controlled network or device conditions", () => { });
|
|
587
|
+
test.skip("[CardDependent] balance() EBT not supported for presented card requires a deterministic non-EBT card routing scenario", () => { });
|
|
588
|
+
test.skip("[PhysicalDevice] balance() with low battery requires a device-level APP013 precondition", () => { });
|
|
589
|
+
});
|
|
590
|
+
// ===========================================================================
|
|
591
|
+
// reverse()
|
|
592
|
+
// References:
|
|
593
|
+
// UpaCreditTests.cs – CreditSale_WhenReversedByTerminalRefNumber_ShouldReturnSuccess
|
|
594
|
+
// Assert.AreEqual("00", reverseResponse.DeviceResponseCode);
|
|
595
|
+
// ===========================================================================
|
|
596
|
+
describeUpaStory2("UPA Story 2 – reverse()", () => {
|
|
597
|
+
let device;
|
|
598
|
+
beforeEach(() => {
|
|
599
|
+
device = DeviceService_1.DeviceService.create(buildConfig());
|
|
600
|
+
device.ecrId = "13";
|
|
601
|
+
});
|
|
602
|
+
/**
|
|
603
|
+
* Mirrors UpaCreditTests.cs – CreditSale_WhenReversedByTerminalRefNumber_ShouldReturnSuccess
|
|
604
|
+
* Assert.IsNotNull(reverseResponse);
|
|
605
|
+
* Assert.AreEqual("00", reverseResponse.DeviceResponseCode);
|
|
606
|
+
*/
|
|
607
|
+
test("[.] reverse() with TerminalRefNumber returns deviceResponseCode == '00'", async () => {
|
|
608
|
+
let response;
|
|
609
|
+
if (useLiveMic) {
|
|
610
|
+
try {
|
|
611
|
+
const saleResponse = await createLiveSale(device);
|
|
612
|
+
if (saleResponse.deviceResponseCode !== "00") {
|
|
613
|
+
if (isKnownLiveSaleBlocker(saleResponse)) {
|
|
614
|
+
console.warn(formatLiveFailure(saleResponse, "Sale"));
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
617
|
+
throw new Error(formatLiveFailure(saleResponse, "Sale"));
|
|
618
|
+
}
|
|
619
|
+
response = await reverseLiveSaleWithRetry(device, saleResponse.terminalRefNumber);
|
|
620
|
+
}
|
|
621
|
+
catch (error) {
|
|
622
|
+
if (isKnownLiveTransportTimeout(error)) {
|
|
623
|
+
console.warn("Reverse live MIC prerequisite timed out while waiting on the device or gateway.");
|
|
624
|
+
return;
|
|
625
|
+
}
|
|
626
|
+
throw error;
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
else {
|
|
630
|
+
response = await device
|
|
631
|
+
.reverse()
|
|
632
|
+
.withTerminalRefNumber("0001234567890123")
|
|
633
|
+
.withEcrId(12)
|
|
634
|
+
.execute();
|
|
635
|
+
}
|
|
636
|
+
expect(response).not.toBeNull();
|
|
637
|
+
expect(response).toBeInstanceOf(TransactionResponse_1.TransactionResponse);
|
|
638
|
+
if (useLiveMic) {
|
|
639
|
+
if (isKnownLiveBusyBlocker(response)) {
|
|
640
|
+
console.warn(formatLiveFailure(response, "Reversal"));
|
|
641
|
+
return;
|
|
642
|
+
}
|
|
643
|
+
expectLiveSuccess(response, ["Reversal", "SendCommand"]);
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
646
|
+
expect(response.deviceResponseCode).toBe("00");
|
|
647
|
+
expect(response.status).toBe("Success");
|
|
648
|
+
});
|
|
649
|
+
// The documented no-tranNo auto-reversal behavior is SI-only. In the current
|
|
650
|
+
// MITC setup this test records the live terminal limitation instead of claiming
|
|
651
|
+
// full spec compliance for the SI fallback path.
|
|
652
|
+
liveOnlyStory2("[LiveSetup] reverse() without tranNo documents current MITC behavior", async () => {
|
|
653
|
+
try {
|
|
654
|
+
const saleResponse = await createLiveSale(device);
|
|
655
|
+
if (saleResponse.deviceResponseCode !== "00") {
|
|
656
|
+
if (isKnownLiveSaleBlocker(saleResponse)) {
|
|
657
|
+
console.warn(formatLiveFailure(saleResponse, "Sale"));
|
|
658
|
+
return;
|
|
659
|
+
}
|
|
660
|
+
throw new Error(formatLiveFailure(saleResponse, "Sale"));
|
|
661
|
+
}
|
|
662
|
+
const response = await reverseLiveSaleWithRetry(device);
|
|
663
|
+
if (isKnownLiveBusyBlocker(response)) {
|
|
664
|
+
console.warn(formatLiveFailure(response, "Reversal auto previous financial transaction"));
|
|
665
|
+
return;
|
|
666
|
+
}
|
|
667
|
+
if (isKnownLiveReverseAutoFallbackBlocker(response)) {
|
|
668
|
+
console.warn("Reverse auto previous financial transaction is not supported in the current MITC configuration; the terminal requires tranNo.");
|
|
669
|
+
return;
|
|
670
|
+
}
|
|
671
|
+
expectLiveSuccess(response, ["Reversal", "SendCommand"]);
|
|
672
|
+
}
|
|
673
|
+
catch (error) {
|
|
674
|
+
if (isKnownLiveTransportTimeout(error)) {
|
|
675
|
+
console.warn("Reverse auto previous financial transaction timed out while waiting on the device or gateway.");
|
|
676
|
+
return;
|
|
677
|
+
}
|
|
678
|
+
throw error;
|
|
679
|
+
}
|
|
680
|
+
});
|
|
681
|
+
liveOnlyStory2("[LivePositive] reverse() returns documented response fields on success", async () => {
|
|
682
|
+
try {
|
|
683
|
+
const saleResponse = await createLiveSale(device);
|
|
684
|
+
if (saleResponse.deviceResponseCode !== "00") {
|
|
685
|
+
if (isKnownLiveSaleBlocker(saleResponse)) {
|
|
686
|
+
console.warn(formatLiveFailure(saleResponse, "Sale"));
|
|
687
|
+
return;
|
|
688
|
+
}
|
|
689
|
+
throw new Error(formatLiveFailure(saleResponse, "Sale"));
|
|
690
|
+
}
|
|
691
|
+
const response = await reverseLiveSaleWithRetry(device, saleResponse.terminalRefNumber);
|
|
692
|
+
if (isKnownLiveBusyBlocker(response)) {
|
|
693
|
+
console.warn(formatLiveFailure(response, "Reversal response field verification"));
|
|
694
|
+
return;
|
|
695
|
+
}
|
|
696
|
+
expectLiveSuccess(response, ["Reversal", "SendCommand"]);
|
|
697
|
+
expectLiveReverseResponseFields(response);
|
|
698
|
+
}
|
|
699
|
+
catch (error) {
|
|
700
|
+
if (isKnownLiveTransportTimeout(error)) {
|
|
701
|
+
console.warn("Reverse response field verification timed out while waiting on the device or gateway.");
|
|
702
|
+
return;
|
|
703
|
+
}
|
|
704
|
+
throw error;
|
|
705
|
+
}
|
|
706
|
+
});
|
|
707
|
+
liveOnlyStory2("[LiveNegative] reverse() already reversed transaction returns failure", async () => {
|
|
708
|
+
try {
|
|
709
|
+
const saleResponse = await createLiveSale(device);
|
|
710
|
+
if (saleResponse.deviceResponseCode !== "00") {
|
|
711
|
+
if (isKnownLiveSaleBlocker(saleResponse)) {
|
|
712
|
+
console.warn(formatLiveFailure(saleResponse, "Sale"));
|
|
713
|
+
return;
|
|
714
|
+
}
|
|
715
|
+
throw new Error(formatLiveFailure(saleResponse, "Sale"));
|
|
716
|
+
}
|
|
717
|
+
const firstReverseResponse = await reverseLiveSaleWithRetry(device, saleResponse.terminalRefNumber);
|
|
718
|
+
if (isKnownLiveBusyBlocker(firstReverseResponse)) {
|
|
719
|
+
console.warn(formatLiveFailure(firstReverseResponse, "Initial reversal"));
|
|
720
|
+
return;
|
|
721
|
+
}
|
|
722
|
+
expectLiveSuccess(firstReverseResponse, ["Reversal", "SendCommand"]);
|
|
723
|
+
await expectLiveReverseFailure(() => reverseLiveSaleWithRetry(device, saleResponse.terminalRefNumber, undefined, 1), "Reversal already reversed transaction");
|
|
724
|
+
}
|
|
725
|
+
catch (error) {
|
|
726
|
+
if (isKnownLiveTransportTimeout(error)) {
|
|
727
|
+
console.warn("Reverse already reversed transaction timed out while waiting on the device or gateway.");
|
|
728
|
+
return;
|
|
729
|
+
}
|
|
730
|
+
throw error;
|
|
731
|
+
}
|
|
732
|
+
});
|
|
733
|
+
liveOnlyStory2("[LiveNegative] reverse() with invalid authorizedAmount returns failure", async () => {
|
|
734
|
+
try {
|
|
735
|
+
const saleResponse = await createLiveSale(device);
|
|
736
|
+
if (saleResponse.deviceResponseCode !== "00") {
|
|
737
|
+
if (isKnownLiveSaleBlocker(saleResponse)) {
|
|
738
|
+
console.warn(formatLiveFailure(saleResponse, "Sale"));
|
|
739
|
+
return;
|
|
740
|
+
}
|
|
741
|
+
throw new Error(formatLiveFailure(saleResponse, "Sale"));
|
|
742
|
+
}
|
|
743
|
+
await expectLiveReverseFailure(() => reverseLiveSaleWithRetry(device, saleResponse.terminalRefNumber, 99.99, 1), "Reversal invalid authorizedAmount");
|
|
744
|
+
}
|
|
745
|
+
catch (error) {
|
|
746
|
+
if (isKnownLiveTransportTimeout(error)) {
|
|
747
|
+
console.warn("Reverse invalid authorizedAmount timed out while waiting on the device or gateway.");
|
|
748
|
+
return;
|
|
749
|
+
}
|
|
750
|
+
throw error;
|
|
751
|
+
}
|
|
752
|
+
});
|
|
753
|
+
liveOnlyStory2("[LivePositive] reverse() debit transaction returns success", async () => {
|
|
754
|
+
try {
|
|
755
|
+
const saleResponse = await createLiveDebitSale(device);
|
|
756
|
+
if (saleResponse.deviceResponseCode !== "00") {
|
|
757
|
+
if (isKnownLiveSaleBlocker(saleResponse)) {
|
|
758
|
+
console.warn(formatLiveFailure(saleResponse, "Debit Sale"));
|
|
759
|
+
return;
|
|
760
|
+
}
|
|
761
|
+
throw new Error(formatLiveFailure(saleResponse, "Debit Sale"));
|
|
762
|
+
}
|
|
763
|
+
const response = await reverseLiveSaleWithRetry(device, saleResponse.terminalRefNumber);
|
|
764
|
+
if (isKnownLiveBusyBlocker(response)) {
|
|
765
|
+
console.warn(formatLiveFailure(response, "Debit Reversal"));
|
|
766
|
+
return;
|
|
767
|
+
}
|
|
768
|
+
expectLiveSuccess(response, ["Reversal", "SendCommand"]);
|
|
769
|
+
expectLiveReverseResponseFields(response);
|
|
770
|
+
if (response.transactionType) {
|
|
771
|
+
expect(response.transactionType.toUpperCase()).toContain("DEBIT");
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
catch (error) {
|
|
775
|
+
if (isKnownLiveTransportTimeout(error)) {
|
|
776
|
+
console.warn("Reverse debit transaction timed out while waiting on the device or gateway.");
|
|
777
|
+
return;
|
|
778
|
+
}
|
|
779
|
+
throw error;
|
|
780
|
+
}
|
|
781
|
+
});
|
|
782
|
+
liveOnlyStory2("[LiveNegative] reverse() with invalid target device returns failure", async () => {
|
|
783
|
+
const unavailableDevice = DeviceService_1.DeviceService.create(buildConfig());
|
|
784
|
+
unavailableDevice.ecrId = "99999999";
|
|
785
|
+
await expectLiveReverseFailure(() => unavailableDevice
|
|
786
|
+
.reverse()
|
|
787
|
+
.withEcrId(99999999)
|
|
788
|
+
.withTerminalRefNumber("0001")
|
|
789
|
+
.execute(), "Reversal invalid target device");
|
|
790
|
+
});
|
|
791
|
+
// The following cases are intentionally left as skipped placeholders because
|
|
792
|
+
// they require SI-only reversal fallback behavior or physical device states
|
|
793
|
+
// that are not reproducible from the current MITC automation setup.
|
|
794
|
+
test.skip("[SIOnly] reverse() after non-financial transaction with no previous financial transaction returns TRAN001", () => { });
|
|
795
|
+
test.skip("[SIOnly] reverse() without tranNo on an already voided transaction returns VOID002", () => { });
|
|
796
|
+
test.skip("[MITCLimit] reverse() not accepted in current state returns a deterministic device error", () => { });
|
|
797
|
+
test.skip("[EnvDependent] reverse() forced timeout scenario requires controlled network or device conditions", () => { });
|
|
798
|
+
test.skip("[PhysicalDevice] reverse() on a not-activated device requires a separately provisioned terminal state", () => { });
|
|
799
|
+
test.skip("[PhysicalDevice] reverse() with low battery requires a device-level battery precondition", () => { });
|
|
800
|
+
});
|
|
801
|
+
// ===========================================================================
|
|
802
|
+
// deletePreAuth()
|
|
803
|
+
// References:
|
|
804
|
+
// UpaCreditTests.cs – DeletePreAuth (TCP)
|
|
805
|
+
// Assert.AreEqual("Success", response.DeviceResponseText);
|
|
806
|
+
// Assert.AreEqual("00", response.DeviceResponseCode);
|
|
807
|
+
// UpaMicTests.cs – CreditDeletePreAuth (MIC — Declined on real device)
|
|
808
|
+
// ===========================================================================
|
|
809
|
+
describeUpaStory2("UPA Story 2 – deletePreAuth()", () => {
|
|
810
|
+
let device;
|
|
811
|
+
beforeEach(() => {
|
|
812
|
+
device = DeviceService_1.DeviceService.create(buildConfig());
|
|
813
|
+
device.ecrId = "13";
|
|
814
|
+
});
|
|
815
|
+
/**
|
|
816
|
+
* Mirrors UpaCreditTests.cs – DeletePreAuth
|
|
817
|
+
* Assert.IsNotNull(response);
|
|
818
|
+
* Assert.AreEqual("Success", response.DeviceResponseText);
|
|
819
|
+
* Assert.AreEqual("00", response.DeviceResponseCode);
|
|
820
|
+
*/
|
|
821
|
+
test("[UpaCreditTests] deletePreAuth() with transactionId and amount returns Success", async () => {
|
|
822
|
+
let response;
|
|
823
|
+
if (useLiveMic) {
|
|
824
|
+
try {
|
|
825
|
+
const preAuthResponse = await createLivePreAuth(device);
|
|
826
|
+
response = await deletePreAuthWithRetry(device, preAuthResponse.transactionId, 1.0);
|
|
827
|
+
}
|
|
828
|
+
catch (error) {
|
|
829
|
+
if (isKnownLiveTransportTimeout(error)) {
|
|
830
|
+
console.warn("DeletePreAuth live MIC prerequisite timed out while waiting on the device or gateway.");
|
|
831
|
+
return;
|
|
832
|
+
}
|
|
833
|
+
throw error;
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
else {
|
|
837
|
+
response = await device
|
|
838
|
+
.deletePreAuth()
|
|
839
|
+
.withEcrId(13)
|
|
840
|
+
.withTransactionId("200071138640")
|
|
841
|
+
.withAmount(1.0)
|
|
842
|
+
.execute();
|
|
843
|
+
}
|
|
844
|
+
expect(response).not.toBeNull();
|
|
845
|
+
expect(response).toBeInstanceOf(TransactionResponse_1.TransactionResponse);
|
|
846
|
+
if (useLiveMic) {
|
|
847
|
+
if (isKnownLiveBusyBlocker(response)) {
|
|
848
|
+
console.warn(formatLiveFailure(response, "DeletePreAuth"));
|
|
849
|
+
return;
|
|
850
|
+
}
|
|
851
|
+
expectLiveSuccess(response, ["DeletePreAuth", "SendCommand"]);
|
|
852
|
+
return;
|
|
853
|
+
}
|
|
854
|
+
expect(response.status).toBe("Success");
|
|
855
|
+
expect(response.deviceResponseText).toBe("Success");
|
|
856
|
+
expect(response.deviceResponseCode).toBe("00");
|
|
857
|
+
});
|
|
858
|
+
liveOnlyStory2("[LiveNegative] deletePreAuth() with unknown reference number returns failure", async () => {
|
|
859
|
+
await expectLiveDeletePreAuthFailure(() => device
|
|
860
|
+
.deletePreAuth()
|
|
861
|
+
.withEcrId(13)
|
|
862
|
+
.withTransactionId("999999999999")
|
|
863
|
+
.withAmount(1.0)
|
|
864
|
+
.execute(), "DeletePreAuth unknown reference number");
|
|
865
|
+
});
|
|
866
|
+
liveOnlyStory2("[LiveNegative] deletePreAuth() without reference number returns failure", async () => {
|
|
867
|
+
await expectLiveDeletePreAuthFailure(() => device
|
|
868
|
+
.deletePreAuth()
|
|
869
|
+
.withEcrId(13)
|
|
870
|
+
.withAmount(1.0)
|
|
871
|
+
.execute(), "DeletePreAuth missing mandatory reference number");
|
|
872
|
+
});
|
|
873
|
+
liveOnlyStory2("[LiveNegative] deletePreAuth() with invalid target device surfaces device error", async () => {
|
|
874
|
+
const unavailableDevice = DeviceService_1.DeviceService.create(buildConfig());
|
|
875
|
+
unavailableDevice.ecrId = "99999999";
|
|
876
|
+
await expectLiveDeletePreAuthFailure(() => unavailableDevice
|
|
877
|
+
.deletePreAuth()
|
|
878
|
+
.withEcrId(99999999)
|
|
879
|
+
.withTransactionId("200015214831")
|
|
880
|
+
.withAmount(1.0)
|
|
881
|
+
.execute(), "DeletePreAuth device error");
|
|
882
|
+
});
|
|
883
|
+
});
|
|
884
|
+
// ===========================================================================
|
|
885
|
+
// startCardTransaction()
|
|
886
|
+
// References:
|
|
887
|
+
// UpaAdminTests.cs – StartCardTransaction_AllCardAcquisitionTypes
|
|
888
|
+
// Assert.AreEqual("Success", response.Status);
|
|
889
|
+
// Assert.AreEqual("00", response.DeviceResponseCode);
|
|
890
|
+
// ===========================================================================
|
|
891
|
+
describeUpaStory2("UPA Story 2 – startCardTransaction()", () => {
|
|
892
|
+
let device;
|
|
893
|
+
beforeEach(() => {
|
|
894
|
+
device = DeviceService_1.DeviceService.create(buildConfig());
|
|
895
|
+
device.ecrId = "13";
|
|
896
|
+
});
|
|
897
|
+
/**
|
|
898
|
+
* Mirrors UpaAdminTests.cs – StartCardTransaction_AllCardAcquisitionTypes
|
|
899
|
+
* Assert.IsNotNull(response);
|
|
900
|
+
* Assert.AreEqual("Success", response.Status);
|
|
901
|
+
test("[UpaAdminTests] startCardTransaction() all acquisition types returns Success", async () => {
|
|
902
|
+
*/
|
|
903
|
+
test("[UpaAdminTests] startCardTransaction() all acquisition types returns Success", async () => {
|
|
904
|
+
const param = new UpaParam_1.UpaParam();
|
|
905
|
+
param.acquisitionTypes = [
|
|
906
|
+
AcquisitionType_1.AcquisitionType.Contact,
|
|
907
|
+
AcquisitionType_1.AcquisitionType.Contactless,
|
|
908
|
+
AcquisitionType_1.AcquisitionType.Swipe,
|
|
909
|
+
AcquisitionType_1.AcquisitionType.Manual,
|
|
910
|
+
];
|
|
911
|
+
param.header = "Sale Transaction";
|
|
912
|
+
param.displayTotalAmount = "Yes";
|
|
913
|
+
param.promptForManual = false;
|
|
914
|
+
param.brandIcon1 = 1;
|
|
915
|
+
param.brandIcon2 = 1;
|
|
916
|
+
param.timeout = 100;
|
|
917
|
+
const indicator = new ProcessIndicator_1.ProcessingIndicator();
|
|
918
|
+
indicator.QuickChip = "Y";
|
|
919
|
+
indicator.CheckLuhn = "N";
|
|
920
|
+
indicator.SecurityCode = "Y";
|
|
921
|
+
indicator.CardTypeFilter = [
|
|
922
|
+
CardTypeFilter_1.CardTypeFilter.VISA,
|
|
923
|
+
CardTypeFilter_1.CardTypeFilter.MC,
|
|
924
|
+
CardTypeFilter_1.CardTypeFilter.AMEX,
|
|
925
|
+
CardTypeFilter_1.CardTypeFilter.DISCOVER,
|
|
926
|
+
];
|
|
927
|
+
const transData = new UpaTransactionData_1.UpaTransactionData();
|
|
928
|
+
transData.totalAmount = 5.0;
|
|
929
|
+
transData.cashBackAmount = 0.0;
|
|
930
|
+
transData.tranDate = new Date();
|
|
931
|
+
transData.tranTime = new Date();
|
|
932
|
+
transData.transType = Enums_2.TransactionType.Sale;
|
|
933
|
+
let response;
|
|
934
|
+
try {
|
|
935
|
+
response = await device.startCardTransaction(param, indicator, transData);
|
|
936
|
+
}
|
|
937
|
+
catch (error) {
|
|
938
|
+
if (useLiveMic && isKnownLiveTransportTimeout(error)) {
|
|
939
|
+
console.warn("StartCardTransaction all acquisition types timed out while waiting on the device or gateway.");
|
|
940
|
+
return;
|
|
941
|
+
}
|
|
942
|
+
throw error;
|
|
943
|
+
}
|
|
944
|
+
expect(response).not.toBeNull();
|
|
945
|
+
expect(response).toBeInstanceOf(UpaGiftCardResponse_1.UpaGiftCardResponse);
|
|
946
|
+
if (useLiveMic) {
|
|
947
|
+
if (isKnownLiveStartCardTransactionBlocker(response)) {
|
|
948
|
+
console.warn(formatLiveFailure(response, "StartCardTransaction all acquisition types"));
|
|
949
|
+
return;
|
|
950
|
+
}
|
|
951
|
+
expectLiveSuccess(response, "StartCardTransaction");
|
|
952
|
+
expectParsedStartCardTransactionResponse(response);
|
|
953
|
+
return;
|
|
954
|
+
}
|
|
955
|
+
expect(response.status).toBe("Success");
|
|
956
|
+
expect(response.deviceResponseCode).toBe("00");
|
|
957
|
+
});
|
|
958
|
+
/**
|
|
959
|
+
* Mirrors UpaAdminTests.cs – StartCardTransaction (basic, swipe only)
|
|
960
|
+
* Assert.IsNotNull(response);
|
|
961
|
+
* Assert.AreEqual("Success", response.Status);
|
|
962
|
+
*/
|
|
963
|
+
test("[UpaAdminTests] startCardTransaction() swipe with GIFT filter returns Success", async () => {
|
|
964
|
+
const param = new UpaParam_1.UpaParam();
|
|
965
|
+
param.timeout = 60;
|
|
966
|
+
param.acquisitionTypes = [AcquisitionType_1.AcquisitionType.Swipe];
|
|
967
|
+
param.header = "Header";
|
|
968
|
+
param.displayTotalAmount = "Y";
|
|
969
|
+
param.promptForManual = true;
|
|
970
|
+
param.brandIcon1 = 4;
|
|
971
|
+
param.brandIcon2 = 3;
|
|
972
|
+
const indicator = new ProcessIndicator_1.ProcessingIndicator();
|
|
973
|
+
indicator.QuickChip = "Y";
|
|
974
|
+
indicator.CheckLuhn = "Y";
|
|
975
|
+
indicator.SecurityCode = "Y";
|
|
976
|
+
indicator.CardTypeFilter = [CardTypeFilter_1.CardTypeFilter.GIFT];
|
|
977
|
+
const transData = new UpaTransactionData_1.UpaTransactionData();
|
|
978
|
+
transData.totalAmount = 11.2;
|
|
979
|
+
transData.cashBackAmount = 2.5;
|
|
980
|
+
transData.tranDate = new Date();
|
|
981
|
+
transData.tranTime = new Date();
|
|
982
|
+
transData.transType = Enums_2.TransactionType.Sale;
|
|
983
|
+
let response;
|
|
984
|
+
try {
|
|
985
|
+
response = await device.startCardTransaction(param, indicator, transData);
|
|
986
|
+
}
|
|
987
|
+
catch (error) {
|
|
988
|
+
if (useLiveMic && isKnownLiveTransportTimeout(error)) {
|
|
989
|
+
console.warn("StartCardTransaction swipe with GIFT filter timed out while waiting on the device or gateway.");
|
|
990
|
+
return;
|
|
991
|
+
}
|
|
992
|
+
throw error;
|
|
993
|
+
}
|
|
994
|
+
expect(response).not.toBeNull();
|
|
995
|
+
if (useLiveMic) {
|
|
996
|
+
if (isKnownLiveGiftCardBlocker(response) ||
|
|
997
|
+
isKnownLiveStartCardTransactionBlocker(response)) {
|
|
998
|
+
console.warn(formatLiveFailure(response, "StartCardTransaction swipe with GIFT filter"));
|
|
999
|
+
return;
|
|
1000
|
+
}
|
|
1001
|
+
expectLiveSuccess(response, "StartCardTransaction");
|
|
1002
|
+
expectParsedStartCardTransactionResponse(response);
|
|
1003
|
+
return;
|
|
1004
|
+
}
|
|
1005
|
+
expect(response.status).toBe("Success");
|
|
1006
|
+
});
|
|
1007
|
+
test("[SdkValidation] startCardTransaction() without acquisitionTypes throws ArgumentError", async () => {
|
|
1008
|
+
const param = new UpaParam_1.UpaParam();
|
|
1009
|
+
param.timeout = 90;
|
|
1010
|
+
param.header = "Missing acquisition types";
|
|
1011
|
+
param.displayTotalAmount = "Yes";
|
|
1012
|
+
const indicator = new ProcessIndicator_1.ProcessingIndicator();
|
|
1013
|
+
indicator.QuickChip = "Y";
|
|
1014
|
+
const transData = new UpaTransactionData_1.UpaTransactionData();
|
|
1015
|
+
transData.totalAmount = 1.0;
|
|
1016
|
+
transData.cashBackAmount = 0.0;
|
|
1017
|
+
transData.tranDate = new Date();
|
|
1018
|
+
transData.tranTime = new Date();
|
|
1019
|
+
transData.transType = Enums_2.TransactionType.Sale;
|
|
1020
|
+
await expect(device.startCardTransaction(param, indicator, transData)).rejects.toMatchObject({
|
|
1021
|
+
name: src_1.ArgumentError.name,
|
|
1022
|
+
message: "acquisitionTypes is required for startCardTransaction",
|
|
1023
|
+
});
|
|
1024
|
+
});
|
|
1025
|
+
test.each([[-1], [Number.NaN], ["invalid"]])("[SdkValidation] startCardTransaction() with invalid totalAmount %p throws ArgumentError", async (invalidTotalAmount) => {
|
|
1026
|
+
const param = new UpaParam_1.UpaParam();
|
|
1027
|
+
param.timeout = 90;
|
|
1028
|
+
param.acquisitionTypes = [AcquisitionType_1.AcquisitionType.Manual];
|
|
1029
|
+
param.header = "Invalid amount";
|
|
1030
|
+
param.displayTotalAmount = "Yes";
|
|
1031
|
+
const indicator = new ProcessIndicator_1.ProcessingIndicator();
|
|
1032
|
+
indicator.QuickChip = "Y";
|
|
1033
|
+
const transData = new UpaTransactionData_1.UpaTransactionData();
|
|
1034
|
+
transData.totalAmount = invalidTotalAmount;
|
|
1035
|
+
transData.cashBackAmount = 0.0;
|
|
1036
|
+
transData.tranDate = new Date();
|
|
1037
|
+
transData.tranTime = new Date();
|
|
1038
|
+
transData.transType = Enums_2.TransactionType.Sale;
|
|
1039
|
+
await expect(device.startCardTransaction(param, indicator, transData)).rejects.toMatchObject({
|
|
1040
|
+
name: src_1.ArgumentError.name,
|
|
1041
|
+
message: "totalAmount must be a non-negative number for startCardTransaction",
|
|
1042
|
+
});
|
|
1043
|
+
});
|
|
1044
|
+
test("[SdkValidation] startCardTransaction() with invalid cardTypeFilter throws ArgumentError", async () => {
|
|
1045
|
+
const param = new UpaParam_1.UpaParam();
|
|
1046
|
+
param.timeout = 90;
|
|
1047
|
+
param.acquisitionTypes = [AcquisitionType_1.AcquisitionType.Manual];
|
|
1048
|
+
param.header = "Invalid card type filter";
|
|
1049
|
+
param.displayTotalAmount = "Yes";
|
|
1050
|
+
const indicator = new ProcessIndicator_1.ProcessingIndicator();
|
|
1051
|
+
indicator.QuickChip = "Y";
|
|
1052
|
+
indicator.CardTypeFilter = ["XYZ"];
|
|
1053
|
+
const transData = new UpaTransactionData_1.UpaTransactionData();
|
|
1054
|
+
transData.totalAmount = 1.0;
|
|
1055
|
+
transData.cashBackAmount = 0.0;
|
|
1056
|
+
transData.tranDate = new Date();
|
|
1057
|
+
transData.tranTime = new Date();
|
|
1058
|
+
transData.transType = Enums_2.TransactionType.Sale;
|
|
1059
|
+
await expect(device.startCardTransaction(param, indicator, transData)).rejects.toMatchObject({
|
|
1060
|
+
name: src_1.ArgumentError.name,
|
|
1061
|
+
message: "cardTypeFilter must contain only supported card types for startCardTransaction",
|
|
1062
|
+
});
|
|
1063
|
+
});
|
|
1064
|
+
liveOnlyStory2("[LiveSetup] startCardTransaction() manual mode with MC filter returns manual entry data", async () => {
|
|
1065
|
+
const param = new UpaParam_1.UpaParam();
|
|
1066
|
+
param.timeout = 90;
|
|
1067
|
+
param.acquisitionTypes = [AcquisitionType_1.AcquisitionType.Manual];
|
|
1068
|
+
param.header = "Manual MC Sale";
|
|
1069
|
+
param.displayTotalAmount = "Yes";
|
|
1070
|
+
param.promptForManual = true;
|
|
1071
|
+
const indicator = new ProcessIndicator_1.ProcessingIndicator();
|
|
1072
|
+
indicator.QuickChip = "Y";
|
|
1073
|
+
indicator.CheckLuhn = "Y";
|
|
1074
|
+
indicator.SecurityCode = "Y";
|
|
1075
|
+
indicator.CardTypeFilter = [CardTypeFilter_1.CardTypeFilter.MC];
|
|
1076
|
+
const transData = new UpaTransactionData_1.UpaTransactionData();
|
|
1077
|
+
transData.totalAmount = 1.0;
|
|
1078
|
+
transData.cashBackAmount = 0.0;
|
|
1079
|
+
transData.tranDate = new Date();
|
|
1080
|
+
transData.tranTime = new Date();
|
|
1081
|
+
transData.transType = Enums_2.TransactionType.Sale;
|
|
1082
|
+
const response = await executeLiveStartCardTransaction(device, param, indicator, transData, "StartCardTransaction manual MC");
|
|
1083
|
+
if (!response) {
|
|
1084
|
+
return;
|
|
1085
|
+
}
|
|
1086
|
+
expect(response.acquisitionType.toUpperCase()).toBe("MANUAL");
|
|
1087
|
+
if (response.cardBrandShortName) {
|
|
1088
|
+
expect(response.cardBrandShortName.toUpperCase()).toBe("MC");
|
|
1089
|
+
}
|
|
1090
|
+
if (response.cardBrand) {
|
|
1091
|
+
expect(response.cardBrand.toUpperCase()).toContain("MASTER");
|
|
1092
|
+
}
|
|
1093
|
+
expect(response.expiryDate).toBeTruthy();
|
|
1094
|
+
expect(response.cvv).toBeTruthy();
|
|
1095
|
+
});
|
|
1096
|
+
liveOnlyStory2("[LiveSetup] startCardTransaction() accepts infinite timeout card entry", async () => {
|
|
1097
|
+
const param = new UpaParam_1.UpaParam();
|
|
1098
|
+
param.timeout = 0;
|
|
1099
|
+
param.acquisitionTypes = [AcquisitionType_1.AcquisitionType.Contact, AcquisitionType_1.AcquisitionType.Swipe];
|
|
1100
|
+
param.header = "Infinite Timeout";
|
|
1101
|
+
param.displayTotalAmount = "Yes";
|
|
1102
|
+
const indicator = new ProcessIndicator_1.ProcessingIndicator();
|
|
1103
|
+
indicator.QuickChip = "Y";
|
|
1104
|
+
indicator.CheckLuhn = "Y";
|
|
1105
|
+
const transData = new UpaTransactionData_1.UpaTransactionData();
|
|
1106
|
+
transData.totalAmount = 1.0;
|
|
1107
|
+
transData.cashBackAmount = 0.0;
|
|
1108
|
+
transData.tranDate = new Date();
|
|
1109
|
+
transData.tranTime = new Date();
|
|
1110
|
+
transData.transType = Enums_2.TransactionType.Sale;
|
|
1111
|
+
const response = await executeLiveStartCardTransaction(device, param, indicator, transData, "StartCardTransaction infinite timeout");
|
|
1112
|
+
if (!response) {
|
|
1113
|
+
return;
|
|
1114
|
+
}
|
|
1115
|
+
expect(response.acquisitionType).toBeTruthy();
|
|
1116
|
+
});
|
|
1117
|
+
liveOnlyStory2("[LiveSetup] startCardTransaction() manual VISA flow returns AVS-capable response data", async () => {
|
|
1118
|
+
const param = new UpaParam_1.UpaParam();
|
|
1119
|
+
param.timeout = 90;
|
|
1120
|
+
param.acquisitionTypes = [AcquisitionType_1.AcquisitionType.Manual];
|
|
1121
|
+
param.header = "Manual VISA Sale";
|
|
1122
|
+
param.displayTotalAmount = "Yes";
|
|
1123
|
+
param.promptForManual = true;
|
|
1124
|
+
const indicator = new ProcessIndicator_1.ProcessingIndicator();
|
|
1125
|
+
indicator.QuickChip = "Y";
|
|
1126
|
+
indicator.CheckLuhn = "Y";
|
|
1127
|
+
indicator.SecurityCode = "Y";
|
|
1128
|
+
indicator.CardTypeFilter = [CardTypeFilter_1.CardTypeFilter.VISA];
|
|
1129
|
+
const transData = new UpaTransactionData_1.UpaTransactionData();
|
|
1130
|
+
transData.totalAmount = 1.0;
|
|
1131
|
+
transData.cashBackAmount = 0.0;
|
|
1132
|
+
transData.tranDate = new Date();
|
|
1133
|
+
transData.tranTime = new Date();
|
|
1134
|
+
transData.transType = Enums_2.TransactionType.Sale;
|
|
1135
|
+
const response = await executeLiveStartCardTransaction(device, param, indicator, transData, "StartCardTransaction manual VISA");
|
|
1136
|
+
if (!response) {
|
|
1137
|
+
return;
|
|
1138
|
+
}
|
|
1139
|
+
expect(response.acquisitionType.toUpperCase()).toBe("MANUAL");
|
|
1140
|
+
if (response.cardBrandShortName) {
|
|
1141
|
+
expect(response.cardBrandShortName.toUpperCase()).toBe("VI");
|
|
1142
|
+
}
|
|
1143
|
+
if (response.cardBrand) {
|
|
1144
|
+
expect(response.cardBrand.toUpperCase()).toContain("VISA");
|
|
1145
|
+
}
|
|
1146
|
+
if (response.avsFlag) {
|
|
1147
|
+
expect(response.avsFlag).toBe("1");
|
|
1148
|
+
}
|
|
1149
|
+
else {
|
|
1150
|
+
console.warn("StartCardTransaction manual VISA did not return AVSFlag on the current device configuration.");
|
|
1151
|
+
}
|
|
1152
|
+
});
|
|
1153
|
+
liveOnlyStory2("[LiveSetup] startCardTransaction() manual AMEX refund flow returns refund card-entry data", async () => {
|
|
1154
|
+
const param = new UpaParam_1.UpaParam();
|
|
1155
|
+
param.timeout = 90;
|
|
1156
|
+
param.acquisitionTypes = [AcquisitionType_1.AcquisitionType.Manual];
|
|
1157
|
+
param.header = "Manual AMEX Refund";
|
|
1158
|
+
param.displayTotalAmount = "Yes";
|
|
1159
|
+
param.promptForManual = true;
|
|
1160
|
+
const indicator = new ProcessIndicator_1.ProcessingIndicator();
|
|
1161
|
+
indicator.QuickChip = "Y";
|
|
1162
|
+
indicator.CheckLuhn = "Y";
|
|
1163
|
+
indicator.SecurityCode = "Y";
|
|
1164
|
+
indicator.CardTypeFilter = [CardTypeFilter_1.CardTypeFilter.AMEX];
|
|
1165
|
+
const transData = new UpaTransactionData_1.UpaTransactionData();
|
|
1166
|
+
transData.totalAmount = 1.0;
|
|
1167
|
+
transData.cashBackAmount = 0.0;
|
|
1168
|
+
transData.tranDate = new Date();
|
|
1169
|
+
transData.tranTime = new Date();
|
|
1170
|
+
transData.transType = Enums_2.TransactionType.Refund;
|
|
1171
|
+
const response = await executeLiveStartCardTransaction(device, param, indicator, transData, "StartCardTransaction manual AMEX refund");
|
|
1172
|
+
if (!response) {
|
|
1173
|
+
return;
|
|
1174
|
+
}
|
|
1175
|
+
expect(response.acquisitionType.toUpperCase()).toBe("MANUAL");
|
|
1176
|
+
if (response.cardBrandShortName &&
|
|
1177
|
+
!["AX", "AMEX"].includes(response.cardBrandShortName.toUpperCase())) {
|
|
1178
|
+
console.warn("StartCardTransaction AMEX refund validation requires an actual AMEX-presented card; the current live run returned a different brand.");
|
|
1179
|
+
return;
|
|
1180
|
+
}
|
|
1181
|
+
if (response.cardBrand &&
|
|
1182
|
+
!response.cardBrand.toUpperCase().includes("AMEX") &&
|
|
1183
|
+
!response.cardBrand.toUpperCase().includes("AMERICAN EXPRESS")) {
|
|
1184
|
+
console.warn("StartCardTransaction AMEX refund validation requires an actual AMEX-presented card; the current live run returned a different brand.");
|
|
1185
|
+
return;
|
|
1186
|
+
}
|
|
1187
|
+
expect(response.expiryDate).toBeTruthy();
|
|
1188
|
+
expect(response.cvv).toBeTruthy();
|
|
1189
|
+
});
|
|
1190
|
+
liveOnlyStory2("[LiveSetup] startCardTransaction() scan mode returns scanned data", async () => {
|
|
1191
|
+
const param = new UpaParam_1.UpaParam();
|
|
1192
|
+
param.timeout = 90;
|
|
1193
|
+
param.acquisitionTypes = [AcquisitionType_1.AcquisitionType.Scan];
|
|
1194
|
+
param.header = "Scan Sale";
|
|
1195
|
+
param.displayTotalAmount = "Yes";
|
|
1196
|
+
const indicator = new ProcessIndicator_1.ProcessingIndicator();
|
|
1197
|
+
indicator.QuickChip = "Y";
|
|
1198
|
+
const transData = new UpaTransactionData_1.UpaTransactionData();
|
|
1199
|
+
transData.totalAmount = 1.0;
|
|
1200
|
+
transData.cashBackAmount = 0.0;
|
|
1201
|
+
transData.tranDate = new Date();
|
|
1202
|
+
transData.tranTime = new Date();
|
|
1203
|
+
transData.transType = Enums_2.TransactionType.Sale;
|
|
1204
|
+
const response = await executeLiveStartCardTransaction(device, param, indicator, transData, "StartCardTransaction scan mode");
|
|
1205
|
+
if (!response) {
|
|
1206
|
+
return;
|
|
1207
|
+
}
|
|
1208
|
+
expect(response.acquisitionType.toUpperCase()).toBe("SCAN");
|
|
1209
|
+
expect(response.scannedData).toBeTruthy();
|
|
1210
|
+
});
|
|
1211
|
+
});
|
|
1212
|
+
// ===========================================================================
|
|
1213
|
+
// reboot()
|
|
1214
|
+
// References:
|
|
1215
|
+
// UpaAdminTests.cs – Reboot: Assert.AreEqual("Success", response.Status)
|
|
1216
|
+
// UpaMicTests.cs – Reboot: Assert.AreEqual("00", response.DeviceResponseCode)
|
|
1217
|
+
// Assert.AreEqual("COMPLETE", response.DeviceResponseText)
|
|
1218
|
+
// (unit test uses mock returning "Success" / "00")
|
|
1219
|
+
// ===========================================================================
|
|
1220
|
+
describeUpaStory2("UPA Story 2 – reboot()", () => {
|
|
1221
|
+
let device;
|
|
1222
|
+
beforeEach(() => {
|
|
1223
|
+
device = DeviceService_1.DeviceService.create(buildConfig());
|
|
1224
|
+
device.ecrId = "13";
|
|
1225
|
+
});
|
|
1226
|
+
/**
|
|
1227
|
+
* Mirrors UpaAdminTests.cs – Reboot + UpaMicTests.cs – Reboot
|
|
1228
|
+
* Assert.IsNotNull(response);
|
|
1229
|
+
* Assert.AreEqual("Success", response.Status);
|
|
1230
|
+
* Assert.AreEqual("00", response.DeviceResponseCode);
|
|
1231
|
+
*/
|
|
1232
|
+
test("[UpaAdminTests][UpaMicTests] reboot() returns Success and does not throw", async () => {
|
|
1233
|
+
const response = await device.reboot();
|
|
1234
|
+
expect(response).not.toBeNull();
|
|
1235
|
+
expect(response).toBeInstanceOf(TransactionResponse_1.TransactionResponse);
|
|
1236
|
+
if (useLiveMic) {
|
|
1237
|
+
expectLiveSuccess(response, "Reboot");
|
|
1238
|
+
return;
|
|
1239
|
+
}
|
|
1240
|
+
expect(response.status).toBe("Success");
|
|
1241
|
+
expect(response.deviceResponseCode).toBe("00");
|
|
1242
|
+
});
|
|
1243
|
+
liveOnlyStory2("[LiveSetup] reboot() on inactive or unresponsive terminal documents current routing behavior", async () => {
|
|
1244
|
+
const unavailableDevice = DeviceService_1.DeviceService.create(buildConfig());
|
|
1245
|
+
unavailableDevice.ecrId = "99999999";
|
|
1246
|
+
try {
|
|
1247
|
+
const response = await unavailableDevice.reboot();
|
|
1248
|
+
expect(response).not.toBeNull();
|
|
1249
|
+
expect(response).toBeInstanceOf(TransactionResponse_1.TransactionResponse);
|
|
1250
|
+
if (isKnownLiveBusyBlocker(response)) {
|
|
1251
|
+
console.warn(formatLiveFailure(response, "Reboot inactive or unresponsive terminal"));
|
|
1252
|
+
return;
|
|
1253
|
+
}
|
|
1254
|
+
if (response.status !== "Success" ||
|
|
1255
|
+
response.deviceResponseCode !== "00" ||
|
|
1256
|
+
(!!response.responseCode && response.responseCode !== "00")) {
|
|
1257
|
+
expect(response.deviceResponseCode).not.toBe("00");
|
|
1258
|
+
return;
|
|
1259
|
+
}
|
|
1260
|
+
console.warn("Reboot inactive or unresponsive terminal scenario was accepted by the current terminal routing configuration.");
|
|
1261
|
+
}
|
|
1262
|
+
catch (error) {
|
|
1263
|
+
if (isKnownLiveTransportTimeout(error)) {
|
|
1264
|
+
console.warn("Reboot inactive or unresponsive terminal timed out while waiting on the device or gateway.");
|
|
1265
|
+
return;
|
|
1266
|
+
}
|
|
1267
|
+
expect(error).toBeInstanceOf(Error);
|
|
1268
|
+
expect(error.message).toBeTruthy();
|
|
1269
|
+
}
|
|
1270
|
+
});
|
|
1271
|
+
test("[Negative] reboot() surfaces network or communication failure", async () => {
|
|
1272
|
+
const communicationFailureDevice = DeviceService_1.DeviceService.create(buildConfig({ serviceUrl: "http://127.0.0.1:1" }), "reboot-communication-failure");
|
|
1273
|
+
communicationFailureDevice.ecrId = "13";
|
|
1274
|
+
await expect(communicationFailureDevice.reboot()).rejects.toBeInstanceOf(Error);
|
|
1275
|
+
});
|
|
1276
|
+
});
|
|
1277
|
+
//# sourceMappingURL=UpaStory2Methods.test.js.map
|