apacuana-sdk-core 1.0.0 → 1.2.0
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/.eslintrc.cjs +22 -0
- package/CHANGELOG.md +1 -0
- package/README.md +794 -0
- package/babel.config.cjs +11 -0
- package/coverage/clover.xml +628 -0
- package/coverage/coverage-final.json +13 -0
- package/coverage/lcov-report/api/index.html +131 -0
- package/coverage/lcov-report/api/signatures.js.html +1093 -0
- package/coverage/lcov-report/api/users.js.html +292 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/certs.js.html +175 -0
- package/coverage/lcov-report/config/index.html +116 -0
- package/coverage/lcov-report/config/index.js.html +208 -0
- package/coverage/lcov-report/errors/index.html +116 -0
- package/coverage/lcov-report/errors/index.js.html +148 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +191 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +210 -0
- package/coverage/lcov-report/src/api/certs.js.html +856 -0
- package/coverage/lcov-report/src/api/faceLiveness.js.html +523 -0
- package/coverage/lcov-report/src/api/index.html +176 -0
- package/coverage/lcov-report/src/api/revocations.js.html +412 -0
- package/coverage/lcov-report/src/api/signatures.js.html +1420 -0
- package/coverage/lcov-report/src/api/users.js.html +466 -0
- package/coverage/lcov-report/src/config/index.html +116 -0
- package/coverage/lcov-report/src/config/index.js.html +256 -0
- package/coverage/lcov-report/src/errors/index.html +116 -0
- package/coverage/lcov-report/src/errors/index.js.html +148 -0
- package/coverage/lcov-report/src/index.html +116 -0
- package/coverage/lcov-report/src/index.js.html +592 -0
- package/coverage/lcov-report/src/success/index.html +116 -0
- package/coverage/lcov-report/src/success/index.js.html +106 -0
- package/coverage/lcov-report/src/utils/constant.js.html +256 -0
- package/coverage/lcov-report/src/utils/helpers.js.html +1195 -0
- package/coverage/lcov-report/src/utils/httpClient.js.html +622 -0
- package/coverage/lcov-report/src/utils/index.html +146 -0
- package/coverage/lcov-report/utils/constant.js.html +145 -0
- package/coverage/lcov-report/utils/httpClient.js.html +646 -0
- package/coverage/lcov-report/utils/index.html +131 -0
- package/coverage/lcov.info +1259 -0
- package/dist/api/certs.d.ts +15 -0
- package/dist/api/faceLiveness.d.ts +6 -0
- package/dist/api/revocations.d.ts +6 -0
- package/dist/api/signatures.d.ts +19 -0
- package/dist/api/users.d.ts +47 -0
- package/dist/config/index.d.ts +22 -0
- package/dist/errors/index.d.ts +10 -0
- package/dist/index.d.ts +25 -0
- package/dist/index.js +34493 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +34491 -0
- package/dist/index.mjs.map +1 -0
- package/dist/success/index.d.ts +7 -0
- package/dist/types/certs.d.ts +83 -0
- package/dist/types/faceLiveness.d.ts +11 -0
- package/dist/types/revocations.d.ts +51 -0
- package/dist/types/signatures.d.ts +162 -0
- package/dist/types/users.d.ts +260 -0
- package/dist/utils/constant.d.ts +49 -0
- package/dist/utils/helpers.d.ts +25 -0
- package/dist/utils/httpClient.d.ts +3 -0
- package/jest.config.cjs +12 -0
- package/package.json +51 -9
- package/rollup.config.js +32 -0
- package/src/api/certs.js +257 -0
- package/src/api/faceLiveness.js +146 -0
- package/src/api/revocations.js +109 -0
- package/src/api/signatures.js +445 -0
- package/src/api/users.js +127 -0
- package/src/config/index.js +57 -0
- package/src/errors/index.js +21 -0
- package/src/index.js +169 -0
- package/src/success/index.js +8 -0
- package/src/types/certs.js +67 -0
- package/src/types/faceLiveness.js +16 -0
- package/src/types/revocations.js +45 -0
- package/src/types/signatures.js +96 -0
- package/src/types/users.js +73 -0
- package/src/utils/constant.js +57 -0
- package/src/utils/helpers.js +370 -0
- package/src/utils/httpClient.js +179 -0
- package/tests/api/certs.test.js +311 -0
- package/tests/api/faceLiveness.test.js +170 -0
- package/tests/api/revocations.test.js +119 -0
- package/tests/api/signatures.test.js +530 -0
- package/tests/api/users.test.js +117 -0
- package/tests/index.test.js +131 -0
- package/tsconfig.json +16 -0
|
@@ -0,0 +1,530 @@
|
|
|
1
|
+
import { getConfig } from "../../src/config";
|
|
2
|
+
import { httpRequest } from "../../src/utils/httpClient";
|
|
3
|
+
import { ApacuanaAPIError } from "../../src/errors";
|
|
4
|
+
import ApacuanaSuccess from "../../src/success";
|
|
5
|
+
import {
|
|
6
|
+
addSigner,
|
|
7
|
+
getDocs,
|
|
8
|
+
getDigest,
|
|
9
|
+
signDocument,
|
|
10
|
+
uploadSignatureVariant,
|
|
11
|
+
getSignatureVariant,
|
|
12
|
+
deleteSignatureVariant,
|
|
13
|
+
} from "../../src/api/signatures";
|
|
14
|
+
import helpers from "../../src/utils/helpers";
|
|
15
|
+
import { INTEGRATION_TYPE } from "../../src/utils/constant";
|
|
16
|
+
|
|
17
|
+
jest.mock("../../src/config");
|
|
18
|
+
jest.mock("../../src/utils/httpClient");
|
|
19
|
+
jest.mock("../../src/utils/helpers", () => ({
|
|
20
|
+
validateOnBoardingSignerData: jest.fn(),
|
|
21
|
+
validateSignOnBoardingData: jest.fn(),
|
|
22
|
+
validateSignOnPremiseData: jest.fn(),
|
|
23
|
+
signDigest: jest.fn(),
|
|
24
|
+
validateGetDocsData: jest.fn(),
|
|
25
|
+
validateGetDigestData: jest.fn(),
|
|
26
|
+
validateOnBoardingSignDocumentData: jest.fn(),
|
|
27
|
+
createPayloadGetDigest: jest.fn(),
|
|
28
|
+
}));
|
|
29
|
+
|
|
30
|
+
describe("API - Signatures", () => {
|
|
31
|
+
beforeAll(() => {
|
|
32
|
+
// FormData no existe en el entorno de Node.js de Jest.
|
|
33
|
+
// Creamos una simulación (mock) que incluye los métodos 'append' y 'forEach'.
|
|
34
|
+
global.FormData = class FormData {
|
|
35
|
+
constructor() {
|
|
36
|
+
this.data = new Map();
|
|
37
|
+
}
|
|
38
|
+
append(key, value) {
|
|
39
|
+
this.data.set(key, value);
|
|
40
|
+
}
|
|
41
|
+
forEach(callback) {
|
|
42
|
+
// Delegamos la llamada forEach al Map interno.
|
|
43
|
+
this.data.forEach((value, key) => callback(value, key));
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
afterAll(() => {
|
|
49
|
+
// Limpiamos la simulación global después de las pruebas.
|
|
50
|
+
delete global.FormData;
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
afterEach(() => {
|
|
54
|
+
jest.resetAllMocks();
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
describe("addSigner", () => {
|
|
58
|
+
it("should call addSignerOnBoarding for ONBOARDING integration", async () => {
|
|
59
|
+
getConfig.mockReturnValue({
|
|
60
|
+
integrationType: INTEGRATION_TYPE.ONBOARDING,
|
|
61
|
+
});
|
|
62
|
+
const signerData = { typedoc: "V", doc: "12345678" };
|
|
63
|
+
|
|
64
|
+
const formData = new FormData();
|
|
65
|
+
formData.append("typedoc", "V");
|
|
66
|
+
formData.append("doc", "12345678");
|
|
67
|
+
|
|
68
|
+
helpers.validateOnBoardingSignerData.mockReturnValue(formData);
|
|
69
|
+
httpRequest.mockResolvedValue({ success: true });
|
|
70
|
+
|
|
71
|
+
await addSigner(signerData);
|
|
72
|
+
|
|
73
|
+
expect(helpers.validateOnBoardingSignerData).toHaveBeenCalledWith(
|
|
74
|
+
signerData
|
|
75
|
+
);
|
|
76
|
+
expect(httpRequest).toHaveBeenCalledWith(
|
|
77
|
+
"services/api/documents/signingsdk",
|
|
78
|
+
formData,
|
|
79
|
+
"POST"
|
|
80
|
+
);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it("should throw not implemented for ONPREMISE integration", async () => {
|
|
84
|
+
getConfig.mockReturnValue({
|
|
85
|
+
integrationType: INTEGRATION_TYPE.ONPREMISE,
|
|
86
|
+
});
|
|
87
|
+
const signerData = { name: "John Doe" };
|
|
88
|
+
|
|
89
|
+
await expect(addSigner(signerData)).rejects.toThrow(
|
|
90
|
+
new ApacuanaAPIError(
|
|
91
|
+
"Adding signers is not supported for integration type: ONPREMISE",
|
|
92
|
+
501,
|
|
93
|
+
"NOT_IMPLEMENTED"
|
|
94
|
+
)
|
|
95
|
+
);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it("should throw an error for unsupported integration type", async () => {
|
|
99
|
+
getConfig.mockReturnValue({ integrationType: "UNSUPPORTED" });
|
|
100
|
+
const signerData = { name: "test" };
|
|
101
|
+
await expect(addSigner(signerData)).rejects.toThrow(
|
|
102
|
+
new ApacuanaAPIError(
|
|
103
|
+
"Unsupported integration type: UNSUPPORTED",
|
|
104
|
+
400,
|
|
105
|
+
"UNSUPPORTED_INTEGRATION_TYPE"
|
|
106
|
+
)
|
|
107
|
+
);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it("should throw an error if signerData is invalid", async () => {
|
|
111
|
+
await expect(addSigner(null)).rejects.toThrow(
|
|
112
|
+
new ApacuanaAPIError(
|
|
113
|
+
"Signer data (signerData) is required and must be a non-empty object.",
|
|
114
|
+
400,
|
|
115
|
+
"INVALID_PARAMETER"
|
|
116
|
+
)
|
|
117
|
+
);
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
describe("getDocs", () => {
|
|
122
|
+
const paginationData = { page: 1, size: 10 };
|
|
123
|
+
|
|
124
|
+
it("should call httpRequest with correct URL when status is provided", async () => {
|
|
125
|
+
getConfig.mockReturnValue({
|
|
126
|
+
integrationType: INTEGRATION_TYPE.ONBOARDING,
|
|
127
|
+
customerId: "test-customer",
|
|
128
|
+
});
|
|
129
|
+
const dataWithStatus = { ...paginationData, status: 1 };
|
|
130
|
+
httpRequest.mockResolvedValue({ docs: [] });
|
|
131
|
+
|
|
132
|
+
await getDocs(dataWithStatus);
|
|
133
|
+
|
|
134
|
+
expect(helpers.validateGetDocsData).toHaveBeenCalledWith(dataWithStatus);
|
|
135
|
+
expect(httpRequest).toHaveBeenCalledWith(
|
|
136
|
+
"services/api/documents/listcustomer?page=1&customerid=test-customer&size=10&status=1",
|
|
137
|
+
{},
|
|
138
|
+
"GET"
|
|
139
|
+
);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it("should throw an error for ONPREMISE integration", async () => {
|
|
143
|
+
getConfig.mockReturnValue({
|
|
144
|
+
integrationType: INTEGRATION_TYPE.ONPREMISE,
|
|
145
|
+
customerId: "test-customer",
|
|
146
|
+
});
|
|
147
|
+
httpRequest.mockResolvedValue({ docs: [] });
|
|
148
|
+
|
|
149
|
+
await expect(getDocs(paginationData)).rejects.toThrow(
|
|
150
|
+
"Document retrieval is not supported for integration type: ONPREMISE"
|
|
151
|
+
);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it("should throw an error if page or size are missing", async () => {
|
|
155
|
+
const validationError = new ApacuanaAPIError(
|
|
156
|
+
"Parameters 'page' and 'size' are required.",
|
|
157
|
+
400,
|
|
158
|
+
"INVALID_PARAMETER"
|
|
159
|
+
);
|
|
160
|
+
helpers.validateGetDocsData.mockImplementation(() => {
|
|
161
|
+
throw validationError;
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
await expect(getDocs({})).rejects.toThrow(validationError);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it("should throw an error if status is invalid", async () => {
|
|
168
|
+
const validationError = new ApacuanaAPIError(
|
|
169
|
+
"Parameter 'status' is not valid.",
|
|
170
|
+
400,
|
|
171
|
+
"INVALID_PARAMETER"
|
|
172
|
+
);
|
|
173
|
+
helpers.validateGetDocsData.mockImplementationOnce(() => {
|
|
174
|
+
throw validationError;
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
await expect(getDocs({ ...paginationData, status: 99 })).rejects.toThrow(
|
|
178
|
+
validationError
|
|
179
|
+
);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it("should throw an error for non-on-premise integrations when customerId is missing", async () => {
|
|
183
|
+
getConfig.mockReturnValue({
|
|
184
|
+
integrationType: INTEGRATION_TYPE.ONBOARDING,
|
|
185
|
+
});
|
|
186
|
+
await expect(getDocs(paginationData)).rejects.toThrow(
|
|
187
|
+
new ApacuanaAPIError(
|
|
188
|
+
"'customerId' is not configured. Please configure the SDK.",
|
|
189
|
+
400,
|
|
190
|
+
"CONFIGURATION_ERROR"
|
|
191
|
+
)
|
|
192
|
+
);
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
describe("getDigest", () => {
|
|
197
|
+
const signData = {
|
|
198
|
+
cert: "test-cert",
|
|
199
|
+
signatureId: "test-signature-id",
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
it("should get digest for ONBOARDING integration", async () => {
|
|
203
|
+
getConfig.mockReturnValue({
|
|
204
|
+
integrationType: INTEGRATION_TYPE.ONBOARDING,
|
|
205
|
+
});
|
|
206
|
+
const mockResponse = { data: { digest: "test-digest" } };
|
|
207
|
+
httpRequest.mockResolvedValue(mockResponse);
|
|
208
|
+
|
|
209
|
+
const expectedFormData = new FormData();
|
|
210
|
+
expectedFormData.append("publickey", "test-cert");
|
|
211
|
+
helpers.createPayloadGetDigest.mockReturnValue(expectedFormData);
|
|
212
|
+
|
|
213
|
+
const result = await getDigest(signData);
|
|
214
|
+
|
|
215
|
+
expect(helpers.validateGetDigestData).toHaveBeenCalledWith(signData);
|
|
216
|
+
expect(helpers.createPayloadGetDigest).toHaveBeenCalledWith(signData);
|
|
217
|
+
expect(httpRequest).toHaveBeenCalledWith(
|
|
218
|
+
`services/api/documents/getdigest/${signData.signatureId}`,
|
|
219
|
+
expectedFormData,
|
|
220
|
+
"POST"
|
|
221
|
+
);
|
|
222
|
+
expect(result).toBeInstanceOf(ApacuanaSuccess);
|
|
223
|
+
expect(result.data).toEqual({ digest: "test-digest" });
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it("should throw an error if digest is not in response for ONBOARDING", async () => {
|
|
227
|
+
getConfig.mockReturnValue({
|
|
228
|
+
integrationType: INTEGRATION_TYPE.ONBOARDING,
|
|
229
|
+
});
|
|
230
|
+
httpRequest.mockResolvedValue({ data: {} });
|
|
231
|
+
|
|
232
|
+
await expect(getDigest(signData)).rejects.toThrow(
|
|
233
|
+
new ApacuanaAPIError(
|
|
234
|
+
"Signature generation failed: digest not found in the response.",
|
|
235
|
+
500,
|
|
236
|
+
"API_RESPONSE_ERROR"
|
|
237
|
+
)
|
|
238
|
+
);
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it("should throw not implemented for ONPREMISE integration", async () => {
|
|
242
|
+
getConfig.mockReturnValue({
|
|
243
|
+
integrationType: INTEGRATION_TYPE.ONPREMISE,
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
await expect(getDigest(signData)).rejects.toThrow(
|
|
247
|
+
new ApacuanaAPIError(
|
|
248
|
+
"Digest retrieval is not supported for integration type: ONPREMISE",
|
|
249
|
+
501,
|
|
250
|
+
"NOT_IMPLEMENTED"
|
|
251
|
+
)
|
|
252
|
+
);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
it("should throw an error for unsupported integration type", async () => {
|
|
256
|
+
getConfig.mockReturnValue({ integrationType: "UNSUPPORTED" });
|
|
257
|
+
await expect(getDigest(signData)).rejects.toThrow(
|
|
258
|
+
"Document retrieval is not supported for an unknown integration type: UNSUPPORTED"
|
|
259
|
+
);
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
describe("signDocument", () => {
|
|
264
|
+
const signData = {
|
|
265
|
+
signature: {
|
|
266
|
+
id: "test-signature-id",
|
|
267
|
+
positions: [{ x: 0.1, y: 0.2, page: 1 }],
|
|
268
|
+
},
|
|
269
|
+
cert: "test-cert",
|
|
270
|
+
signedDigest: "test-signed-digest",
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
it("should sign document for ONBOARDING integration", async () => {
|
|
274
|
+
getConfig.mockReturnValue({
|
|
275
|
+
integrationType: INTEGRATION_TYPE.ONBOARDING,
|
|
276
|
+
});
|
|
277
|
+
const mockResponse = { success: true };
|
|
278
|
+
httpRequest.mockResolvedValue(mockResponse);
|
|
279
|
+
|
|
280
|
+
const expectedFormData = new FormData();
|
|
281
|
+
expectedFormData.append(
|
|
282
|
+
"positions",
|
|
283
|
+
JSON.stringify(
|
|
284
|
+
signData.signature.positions.map((p) => ({
|
|
285
|
+
x: p.x,
|
|
286
|
+
y: p.y,
|
|
287
|
+
page: p.page,
|
|
288
|
+
status: 1,
|
|
289
|
+
}))
|
|
290
|
+
)
|
|
291
|
+
);
|
|
292
|
+
expectedFormData.append("publickey", signData.cert);
|
|
293
|
+
expectedFormData.append("signeddigest", signData.signedDigest);
|
|
294
|
+
|
|
295
|
+
helpers.validateOnBoardingSignDocumentData.mockReturnValue(
|
|
296
|
+
expectedFormData
|
|
297
|
+
);
|
|
298
|
+
|
|
299
|
+
const result = await signDocument(signData);
|
|
300
|
+
|
|
301
|
+
expect(helpers.validateOnBoardingSignDocumentData).toHaveBeenCalledWith(
|
|
302
|
+
signData
|
|
303
|
+
);
|
|
304
|
+
expect(httpRequest).toHaveBeenCalledWith(
|
|
305
|
+
`services/api/documents/sign/${signData.signature.id}`,
|
|
306
|
+
expectedFormData,
|
|
307
|
+
"PUT"
|
|
308
|
+
);
|
|
309
|
+
expect(result).toBeInstanceOf(ApacuanaSuccess);
|
|
310
|
+
expect(result.data).toEqual(mockResponse);
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
it("should throw not implemented for ONPREMISE integration", async () => {
|
|
314
|
+
getConfig.mockReturnValue({
|
|
315
|
+
integrationType: INTEGRATION_TYPE.ONPREMISE,
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
await expect(signDocument(signData)).rejects.toThrow(
|
|
319
|
+
new ApacuanaAPIError(
|
|
320
|
+
"Document signing is not supported for integration type: ONPREMISE",
|
|
321
|
+
501,
|
|
322
|
+
"NOT_IMPLEMENTED"
|
|
323
|
+
)
|
|
324
|
+
);
|
|
325
|
+
});
|
|
326
|
+
|
|
327
|
+
it("should throw an error for unsupported integration type", async () => {
|
|
328
|
+
getConfig.mockReturnValue({ integrationType: "UNSUPPORTED" });
|
|
329
|
+
await expect(signDocument(signData)).rejects.toThrow(
|
|
330
|
+
new ApacuanaAPIError(
|
|
331
|
+
"Unsupported integration type: UNSUPPORTED",
|
|
332
|
+
400,
|
|
333
|
+
"UNSUPPORTED_INTEGRATION_TYPE"
|
|
334
|
+
)
|
|
335
|
+
);
|
|
336
|
+
});
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
describe("uploadSignatureVariant", () => {
|
|
340
|
+
beforeAll(() => {
|
|
341
|
+
// Define a global mock for File to simulate a browser environment
|
|
342
|
+
global.File = class MockFile {
|
|
343
|
+
constructor(parts, filename, options) {
|
|
344
|
+
this.type = options ? options.type : "";
|
|
345
|
+
}
|
|
346
|
+
};
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
afterAll(() => {
|
|
350
|
+
// Clean up the global mock
|
|
351
|
+
delete global.File;
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
it("should throw an error if data or data.file is not provided", async () => {
|
|
355
|
+
await expect(uploadSignatureVariant(null)).rejects.toThrow(
|
|
356
|
+
new ApacuanaAPIError(
|
|
357
|
+
"El parámetro 'file' es requerido.",
|
|
358
|
+
400,
|
|
359
|
+
"INVALID_PARAMETER"
|
|
360
|
+
)
|
|
361
|
+
);
|
|
362
|
+
await expect(uploadSignatureVariant({})).rejects.toThrow(
|
|
363
|
+
new ApacuanaAPIError(
|
|
364
|
+
"El parámetro 'file' es requerido.",
|
|
365
|
+
400,
|
|
366
|
+
"INVALID_PARAMETER"
|
|
367
|
+
)
|
|
368
|
+
);
|
|
369
|
+
});
|
|
370
|
+
|
|
371
|
+
it("should throw an error if file is not a File instance", async () => {
|
|
372
|
+
await expect(uploadSignatureVariant({ file: {} })).rejects.toThrow(
|
|
373
|
+
new ApacuanaAPIError(
|
|
374
|
+
"El parámetro 'file' debe ser una instancia de 'File'.",
|
|
375
|
+
400,
|
|
376
|
+
"INVALID_PARAMETER"
|
|
377
|
+
)
|
|
378
|
+
);
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
it("should throw an error if file is not a PNG", async () => {
|
|
382
|
+
const invalidFile = new File([], "test.txt", { type: "text/plain" });
|
|
383
|
+
await expect(
|
|
384
|
+
uploadSignatureVariant({ file: invalidFile })
|
|
385
|
+
).rejects.toThrow(
|
|
386
|
+
new ApacuanaAPIError(
|
|
387
|
+
"El archivo debe ser de tipo PNG (image/png).",
|
|
388
|
+
400,
|
|
389
|
+
"INVALID_PARAMETER"
|
|
390
|
+
)
|
|
391
|
+
);
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
it("should upload file for ONBOARDING integration", async () => {
|
|
395
|
+
getConfig.mockReturnValue({
|
|
396
|
+
integrationType: INTEGRATION_TYPE.ONBOARDING,
|
|
397
|
+
});
|
|
398
|
+
const validFile = new File([], "signature.png", { type: "image/png" });
|
|
399
|
+
const data = { file: validFile };
|
|
400
|
+
httpRequest.mockResolvedValue({ success: true, id: "123" });
|
|
401
|
+
|
|
402
|
+
const result = await uploadSignatureVariant(data);
|
|
403
|
+
|
|
404
|
+
expect(httpRequest).toHaveBeenCalledWith(
|
|
405
|
+
"services/api/customer/signaturephoto",
|
|
406
|
+
{ file: validFile },
|
|
407
|
+
"POST"
|
|
408
|
+
);
|
|
409
|
+
expect(result).toBeInstanceOf(ApacuanaSuccess);
|
|
410
|
+
expect(result.data).toEqual({ success: true, id: "123" });
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
it("should throw not implemented for ONPREMISE integration", async () => {
|
|
414
|
+
getConfig.mockReturnValue({
|
|
415
|
+
integrationType: INTEGRATION_TYPE.ONPREMISE,
|
|
416
|
+
});
|
|
417
|
+
const validFile = new File([], "signature.png", { type: "image/png" });
|
|
418
|
+
await expect(uploadSignatureVariant({ file: validFile })).rejects.toThrow(
|
|
419
|
+
new ApacuanaAPIError(
|
|
420
|
+
"Uploading signature variants is not supported for integration type: ONPREMISE",
|
|
421
|
+
501,
|
|
422
|
+
"NOT_IMPLEMENTED"
|
|
423
|
+
)
|
|
424
|
+
);
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
it("should throw an error for unsupported integration type", async () => {
|
|
428
|
+
getConfig.mockReturnValue({ integrationType: "UNSUPPORTED" });
|
|
429
|
+
const validFile = new File([], "signature.png", { type: "image/png" });
|
|
430
|
+
await expect(uploadSignatureVariant({ file: validFile })).rejects.toThrow(
|
|
431
|
+
new ApacuanaAPIError(
|
|
432
|
+
"Unsupported integration type: UNSUPPORTED",
|
|
433
|
+
400,
|
|
434
|
+
"UNSUPPORTED_INTEGRATION_TYPE"
|
|
435
|
+
)
|
|
436
|
+
);
|
|
437
|
+
});
|
|
438
|
+
});
|
|
439
|
+
|
|
440
|
+
describe("getSignatureVariant", () => {
|
|
441
|
+
it("should get signature variant for ONBOARDING integration", async () => {
|
|
442
|
+
getConfig.mockReturnValue({
|
|
443
|
+
integrationType: INTEGRATION_TYPE.ONBOARDING,
|
|
444
|
+
customerId: "test-customer",
|
|
445
|
+
});
|
|
446
|
+
const mockResponse = { success: true, file: "base64-encoded-file" };
|
|
447
|
+
httpRequest.mockResolvedValue(mockResponse);
|
|
448
|
+
|
|
449
|
+
const result = await getSignatureVariant();
|
|
450
|
+
|
|
451
|
+
expect(httpRequest).toHaveBeenCalledWith(
|
|
452
|
+
"services/api/customer/getsignaturephotosdk/test-customer",
|
|
453
|
+
{},
|
|
454
|
+
"GET"
|
|
455
|
+
);
|
|
456
|
+
expect(result).toBeInstanceOf(ApacuanaSuccess);
|
|
457
|
+
expect(result.data).toEqual(mockResponse);
|
|
458
|
+
});
|
|
459
|
+
|
|
460
|
+
it("should throw not implemented for ONPREMISE integration", async () => {
|
|
461
|
+
getConfig.mockReturnValue({
|
|
462
|
+
integrationType: INTEGRATION_TYPE.ONPREMISE,
|
|
463
|
+
});
|
|
464
|
+
|
|
465
|
+
await expect(getSignatureVariant()).rejects.toThrow(
|
|
466
|
+
new ApacuanaAPIError(
|
|
467
|
+
"Getting signature variants is not supported for integration type: ONPREMISE",
|
|
468
|
+
501,
|
|
469
|
+
"NOT_IMPLEMENTED"
|
|
470
|
+
)
|
|
471
|
+
);
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
it("should throw an error for unsupported integration type", async () => {
|
|
475
|
+
getConfig.mockReturnValue({ integrationType: "UNSUPPORTED" });
|
|
476
|
+
await expect(getSignatureVariant()).rejects.toThrow(
|
|
477
|
+
new ApacuanaAPIError(
|
|
478
|
+
"Unsupported integration type: UNSUPPORTED",
|
|
479
|
+
400,
|
|
480
|
+
"UNSUPPORTED_INTEGRATION_TYPE"
|
|
481
|
+
)
|
|
482
|
+
);
|
|
483
|
+
});
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
describe("deleteSignatureVariant", () => {
|
|
487
|
+
it("should delete signature variant for ONBOARDING integration", async () => {
|
|
488
|
+
getConfig.mockReturnValue({
|
|
489
|
+
integrationType: INTEGRATION_TYPE.ONBOARDING,
|
|
490
|
+
});
|
|
491
|
+
const mockResponse = { success: true, message: "Deleted" };
|
|
492
|
+
httpRequest.mockResolvedValue(mockResponse);
|
|
493
|
+
|
|
494
|
+
const result = await deleteSignatureVariant();
|
|
495
|
+
|
|
496
|
+
expect(httpRequest).toHaveBeenCalledWith(
|
|
497
|
+
"services/api/customer/cleansignaturephoto",
|
|
498
|
+
{},
|
|
499
|
+
"DELETE"
|
|
500
|
+
);
|
|
501
|
+
expect(result).toBeInstanceOf(ApacuanaSuccess);
|
|
502
|
+
expect(result.data).toEqual(mockResponse);
|
|
503
|
+
});
|
|
504
|
+
|
|
505
|
+
it("should throw not implemented for ONPREMISE integration", async () => {
|
|
506
|
+
getConfig.mockReturnValue({
|
|
507
|
+
integrationType: INTEGRATION_TYPE.ONPREMISE,
|
|
508
|
+
});
|
|
509
|
+
|
|
510
|
+
await expect(deleteSignatureVariant()).rejects.toThrow(
|
|
511
|
+
new ApacuanaAPIError(
|
|
512
|
+
"Deleting signature variants is not supported for integration type: ONPREMISE",
|
|
513
|
+
501,
|
|
514
|
+
"NOT_IMPLEMENTED"
|
|
515
|
+
)
|
|
516
|
+
);
|
|
517
|
+
});
|
|
518
|
+
|
|
519
|
+
it("should throw an error for unsupported integration type", async () => {
|
|
520
|
+
getConfig.mockReturnValue({ integrationType: "UNSUPPORTED" });
|
|
521
|
+
await expect(deleteSignatureVariant()).rejects.toThrow(
|
|
522
|
+
new ApacuanaAPIError(
|
|
523
|
+
"Unsupported integration type: UNSUPPORTED",
|
|
524
|
+
400,
|
|
525
|
+
"UNSUPPORTED_INTEGRATION_TYPE"
|
|
526
|
+
)
|
|
527
|
+
);
|
|
528
|
+
});
|
|
529
|
+
});
|
|
530
|
+
});
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
// tests/api/users.test.js
|
|
2
|
+
import { httpRequest } from "../../src/utils/httpClient.js";
|
|
3
|
+
import { getConfig } from "../../src/config/index.js";
|
|
4
|
+
import { ApacuanaAPIError } from "../../src/errors/index.js";
|
|
5
|
+
import ApacuanaSuccess from "../../src/success/index.js";
|
|
6
|
+
import { getCustomer } from "../../src/api/users.js";
|
|
7
|
+
|
|
8
|
+
// Mockear las dependencias:
|
|
9
|
+
jest.mock("../../src/utils/httpClient.js", () => ({
|
|
10
|
+
httpRequest: jest.fn(),
|
|
11
|
+
}));
|
|
12
|
+
|
|
13
|
+
jest.mock("../../src/config/index.js", () => ({
|
|
14
|
+
getConfig: jest.fn(),
|
|
15
|
+
}));
|
|
16
|
+
|
|
17
|
+
describe("getCustomer", () => {
|
|
18
|
+
const mockConfig = {
|
|
19
|
+
verificationId: "mock-verify-id",
|
|
20
|
+
customerId: "mock-customer-id",
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
beforeEach(() => {
|
|
24
|
+
httpRequest.mockClear();
|
|
25
|
+
getConfig.mockClear();
|
|
26
|
+
getConfig.mockReturnValue(mockConfig);
|
|
27
|
+
jest.spyOn(console, "log").mockImplementation(() => {});
|
|
28
|
+
jest.spyOn(console, "error").mockImplementation(() => {});
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
afterEach(() => {
|
|
32
|
+
console.log.mockRestore();
|
|
33
|
+
console.error.mockRestore();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test("debe llamar a httpRequest con los parámetros de la configuración y devolver un objeto con token y userData", async () => {
|
|
37
|
+
const mockResponse = {
|
|
38
|
+
success: true,
|
|
39
|
+
sessionid: "mock-session-id-12345",
|
|
40
|
+
entry: {
|
|
41
|
+
userId: "mock-user",
|
|
42
|
+
name: "John Doe",
|
|
43
|
+
email: "john@example.com",
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
httpRequest.mockResolvedValueOnce(mockResponse);
|
|
47
|
+
|
|
48
|
+
const result = await getCustomer();
|
|
49
|
+
|
|
50
|
+
expect(httpRequest).toHaveBeenCalledTimes(1);
|
|
51
|
+
expect(httpRequest).toHaveBeenCalledWith(
|
|
52
|
+
"services/api/register/init",
|
|
53
|
+
{
|
|
54
|
+
verificationid: mockConfig.verificationId,
|
|
55
|
+
customerid: mockConfig.customerId,
|
|
56
|
+
},
|
|
57
|
+
"POST"
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
expect(result).toBeInstanceOf(ApacuanaSuccess);
|
|
61
|
+
expect(result.data).toEqual({
|
|
62
|
+
token: "mock-session-id-12345",
|
|
63
|
+
userData: {
|
|
64
|
+
userId: "mock-user",
|
|
65
|
+
name: "John Doe",
|
|
66
|
+
email: "john@example.com",
|
|
67
|
+
},
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test("should throw an error if configuration is incomplete", async () => {
|
|
72
|
+
getConfig.mockReturnValue({
|
|
73
|
+
verificationId: "mock-verify-id",
|
|
74
|
+
customerId: null,
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
await expect(getCustomer()).rejects.toThrow(
|
|
78
|
+
"Both 'verificationId' and 'customerId' must be configured."
|
|
79
|
+
);
|
|
80
|
+
expect(httpRequest).not.toHaveBeenCalled();
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
test("should throw ApacuanaAPIError if backend does not return sessionid or entry", async () => {
|
|
84
|
+
httpRequest.mockResolvedValueOnce({
|
|
85
|
+
success: true,
|
|
86
|
+
message: "Backend error, token could not be generated.",
|
|
87
|
+
entry: { userId: "mock-user" },
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
await expect(getCustomer()).rejects.toThrow(
|
|
91
|
+
"The API response does not contain the user."
|
|
92
|
+
);
|
|
93
|
+
expect(httpRequest).toHaveBeenCalledTimes(1);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
test("should rethrow ApacuanaAPIError if httpClient request fails", async () => {
|
|
97
|
+
const apiError = new ApacuanaAPIError(
|
|
98
|
+
"Authentication error",
|
|
99
|
+
401,
|
|
100
|
+
"AUTH_ERROR"
|
|
101
|
+
);
|
|
102
|
+
httpRequest.mockRejectedValueOnce(apiError);
|
|
103
|
+
|
|
104
|
+
await expect(getCustomer()).rejects.toThrow(apiError);
|
|
105
|
+
expect(httpRequest).toHaveBeenCalledTimes(1);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test("should throw ApacuanaAPIError on unexpected error", async () => {
|
|
109
|
+
const genericError = new Error("Network or unknown error");
|
|
110
|
+
httpRequest.mockRejectedValueOnce(genericError);
|
|
111
|
+
|
|
112
|
+
await expect(getCustomer()).rejects.toThrow(
|
|
113
|
+
"Unexpected failure getting token: Network or unknown error"
|
|
114
|
+
);
|
|
115
|
+
expect(httpRequest).toHaveBeenCalledTimes(1);
|
|
116
|
+
});
|
|
117
|
+
});
|