apacuana-sdk-core 0.11.0 → 0.13.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/README.md +131 -164
- package/coverage/clover.xml +338 -302
- package/coverage/coverage-final.json +9 -9
- package/coverage/lcov-report/index.html +31 -31
- package/coverage/lcov-report/src/api/certs.js.html +1 -1
- package/coverage/lcov-report/src/api/faceLiveness.js.html +34 -7
- package/coverage/lcov-report/src/api/index.html +13 -13
- package/coverage/lcov-report/src/api/revocations.js.html +50 -5
- package/coverage/lcov-report/src/api/signatures.js.html +17 -56
- package/coverage/lcov-report/src/api/users.js.html +20 -5
- package/coverage/lcov-report/src/config/index.html +1 -1
- package/coverage/lcov-report/src/config/index.js.html +1 -1
- package/coverage/lcov-report/src/errors/index.html +1 -1
- package/coverage/lcov-report/src/errors/index.js.html +8 -8
- package/coverage/lcov-report/src/index.html +13 -13
- package/coverage/lcov-report/src/index.js.html +59 -14
- package/coverage/lcov-report/src/success/index.html +1 -1
- package/coverage/lcov-report/src/success/index.js.html +5 -5
- package/coverage/lcov-report/src/utils/constant.js.html +1 -1
- package/coverage/lcov-report/src/utils/helpers.js.html +277 -16
- package/coverage/lcov-report/src/utils/httpClient.js.html +32 -17
- package/coverage/lcov-report/src/utils/index.html +22 -22
- package/coverage/lcov.info +641 -561
- package/dist/api/revocations.d.ts +6 -3
- package/dist/api/users.d.ts +16 -6
- package/dist/index.d.ts +0 -2
- package/dist/index.js +149 -147
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +149 -147
- package/dist/index.mjs.map +1 -1
- package/dist/types/faceLiveness.d.ts +6 -5
- package/dist/types/revocations.d.ts +26 -15
- package/dist/types/signatures.d.ts +73 -63
- package/dist/utils/helpers.d.ts +4 -2
- package/package.json +1 -1
- package/src/api/faceLiveness.js +13 -4
- package/src/api/revocations.js +18 -3
- package/src/api/signatures.js +8 -21
- package/src/api/users.js +8 -3
- package/src/index.js +22 -7
- package/src/types/faceLiveness.js +11 -2
- package/src/types/revocations.js +29 -9
- package/src/types/signatures.js +47 -28
- package/src/utils/helpers.js +95 -8
- package/src/utils/httpClient.js +15 -10
- package/tests/api/faceLiveness.test.js +28 -30
- package/tests/api/revocations.test.js +4 -4
- package/tests/api/signatures.test.js +73 -16
- package/tests/index.test.js +16 -8
package/src/types/signatures.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {import('../success').ApacuanaSuccess} ApacuanaSuccess
|
|
3
|
+
*/
|
|
4
|
+
|
|
1
5
|
/**
|
|
2
6
|
* Define la estructura de un objeto Firmante.
|
|
3
7
|
* @typedef {object} Signer
|
|
@@ -7,30 +11,54 @@
|
|
|
7
11
|
*/
|
|
8
12
|
|
|
9
13
|
/**
|
|
10
|
-
*
|
|
11
|
-
* @
|
|
12
|
-
* @property {string} docId - Identificador único del documento.
|
|
14
|
+
* @typedef {object} AddSignerData
|
|
15
|
+
* @property {string} signer - Identificador de confirmación del firmante añadido.
|
|
13
16
|
*/
|
|
14
17
|
|
|
15
18
|
/**
|
|
16
19
|
* Define la estructura de la respuesta al añadir un firmante.
|
|
17
20
|
* @typedef {object} AddSignerResponse
|
|
18
|
-
* @property {
|
|
19
|
-
* @property {
|
|
21
|
+
* @property {true} success
|
|
22
|
+
* @property {AddSignerData} data
|
|
20
23
|
*/
|
|
21
24
|
|
|
22
25
|
/**
|
|
23
26
|
* Define la estructura de datos para obtener el digest de un documento.
|
|
24
27
|
* @typedef {object} GetDigestData
|
|
25
28
|
* @property {string} cert - Certificado del firmante en formato base64.
|
|
26
|
-
* @property {string} signatureId - Identificador único
|
|
29
|
+
* @property {string} signatureId - Identificador único de la firma.
|
|
30
|
+
* @property {File} [document] - Documento a firmar en formato de archivo. Este campo es opcional.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @typedef {object} SignaturePlacement
|
|
35
|
+
* @property {number} page - Página donde se estampará la firma.
|
|
36
|
+
* @property {number} x - Coordenada X de la firma.
|
|
37
|
+
* @property {number} y - Coordenada Y de la firma.
|
|
38
|
+
*/
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Define la estructura de datos para añadir un firmante.
|
|
42
|
+
* @typedef {object} SignerData
|
|
43
|
+
* @property {string} name - Nombre del firmante.
|
|
44
|
+
* @property {string} typedoc - Tipo de documento de identidad del firmante.
|
|
45
|
+
* @property {string} doc - Número de documento de identidad del firmante.
|
|
46
|
+
* @property {Array<SignaturePlacement>} signature - Array con las coordenadas donde se estampará la firma.
|
|
47
|
+
* @property {string} [reference] - Referencia a un documento pre-cargado. Se debe proporcionar 'reference' o 'file', pero no ambos.
|
|
48
|
+
* @property {File} [file] - Archivo del documento a firmar. Se debe proporcionar 'reference' o 'file', pero no ambos.
|
|
49
|
+
*/
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Define la estructura de datos para la respuesta de la creación de una firma.
|
|
53
|
+
* @typedef {object} GetDigestResponseData
|
|
54
|
+
* @property {string} digest - El digest del documento que se va a firmar.
|
|
27
55
|
*/
|
|
28
56
|
|
|
29
57
|
/**
|
|
30
58
|
* Define la estructura de la respuesta al obtener el digest.
|
|
31
59
|
* @typedef {object} GetDigestResponse
|
|
32
|
-
* @property {
|
|
33
|
-
* @property {
|
|
60
|
+
* @property {true} success
|
|
61
|
+
* @property {GetDigestResponseData} data
|
|
34
62
|
*/
|
|
35
63
|
|
|
36
64
|
/**
|
|
@@ -42,11 +70,16 @@
|
|
|
42
70
|
*/
|
|
43
71
|
|
|
44
72
|
/**
|
|
45
|
-
*
|
|
46
|
-
* @typedef {object} GetDocsResponse
|
|
73
|
+
* @typedef {object} GetDocsResponseData
|
|
47
74
|
* @property {number} totalRecords - El número total de registros encontrados.
|
|
48
75
|
* @property {Array<object>} records - Un arreglo con los registros de los documentos.
|
|
49
|
-
|
|
76
|
+
*/
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Define la estructura de la respuesta al obtener documentos.
|
|
80
|
+
* @typedef {object} GetDocsResponse
|
|
81
|
+
* @property {true} success
|
|
82
|
+
* @property {GetDocsResponseData} data
|
|
50
83
|
*/
|
|
51
84
|
|
|
52
85
|
/**
|
|
@@ -56,22 +89,8 @@
|
|
|
56
89
|
* @property {Array<object>} signature.positions - Posiciones de la firma.
|
|
57
90
|
* @property {string} cert - Certificado en base64.
|
|
58
91
|
* @property {string} signedDigest - Digest firmado.
|
|
92
|
+
* @property {File} [document] - Documento a firmar en formato de archivo. Este campo es opcional.
|
|
93
|
+
|
|
59
94
|
*/
|
|
60
95
|
|
|
61
|
-
|
|
62
|
-
* @typedef {object} SignaturePosition
|
|
63
|
-
* @property {number} page - The page number for the signature.
|
|
64
|
-
* @property {number} x - The x-coordinate for the signature's position (from 0 to 1).
|
|
65
|
-
* @property {number} y - The y-coordinate for the signature's position (from 0 to 1).
|
|
66
|
-
*/
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* @typedef {object} OnboardingSignerData
|
|
70
|
-
* @property {string} name - The name of the document.
|
|
71
|
-
* @property {string} reference - An external reference for the document.
|
|
72
|
-
* @property {string} typedoc - The type of document of the signer (e.g., "V", "E", "J").
|
|
73
|
-
* @property {string} doc - The document number of the signer.
|
|
74
|
-
* @property {SignaturePosition[]} signature - An array of signature positions.
|
|
75
|
-
*/
|
|
76
|
-
|
|
77
|
-
export {};
|
|
96
|
+
export {};
|
package/src/utils/helpers.js
CHANGED
|
@@ -65,8 +65,31 @@ const encryptedCsr = (csr, encryptKey = KEY_HEX) => {
|
|
|
65
65
|
return body;
|
|
66
66
|
};
|
|
67
67
|
|
|
68
|
+
const createPayloadGetDigest = (signData) => {
|
|
69
|
+
const formData = new FormData();
|
|
70
|
+
|
|
71
|
+
// Iterate over the object's own properties
|
|
72
|
+
Object.keys(signData).forEach((key) => {
|
|
73
|
+
// Conditionally handle the 'document' field
|
|
74
|
+
|
|
75
|
+
if (key === "document" && signData[key] instanceof File) {
|
|
76
|
+
// Append the file directly
|
|
77
|
+
formData.append(key, signData[key]);
|
|
78
|
+
} else if (key === "cert") {
|
|
79
|
+
formData.append("publickey", signData[key]);
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
return formData;
|
|
83
|
+
};
|
|
84
|
+
|
|
68
85
|
const validateOnBoardingSignerData = (signerData) => {
|
|
69
|
-
|
|
86
|
+
// Create a copy of the original object to avoid modifying the function parameter
|
|
87
|
+
const validatedSignerData = { ...signerData };
|
|
88
|
+
|
|
89
|
+
if (
|
|
90
|
+
!validatedSignerData.name ||
|
|
91
|
+
typeof validatedSignerData.name !== "string"
|
|
92
|
+
) {
|
|
70
93
|
throw new ApacuanaAPIError(
|
|
71
94
|
'El campo "name" es requerido y debe ser una cadena de texto.',
|
|
72
95
|
400,
|
|
@@ -74,16 +97,46 @@ const validateOnBoardingSignerData = (signerData) => {
|
|
|
74
97
|
);
|
|
75
98
|
}
|
|
76
99
|
|
|
77
|
-
|
|
100
|
+
// Limpia 'reference' si es inválido o está vacío.
|
|
101
|
+
if (
|
|
102
|
+
!validatedSignerData.reference ||
|
|
103
|
+
typeof validatedSignerData.reference !== "string" ||
|
|
104
|
+
validatedSignerData.reference.trim() === ""
|
|
105
|
+
) {
|
|
106
|
+
delete validatedSignerData.reference;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Limpia 'file' si no es una instancia de File.
|
|
110
|
+
if (
|
|
111
|
+
typeof File === "undefined" ||
|
|
112
|
+
!validatedSignerData.file ||
|
|
113
|
+
!(validatedSignerData.file instanceof File)
|
|
114
|
+
) {
|
|
115
|
+
delete validatedSignerData.file;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
// Valida que solo uno de los dos campos exista después de la limpieza.
|
|
119
|
+
if (validatedSignerData.reference && validatedSignerData.file) {
|
|
120
|
+
throw new ApacuanaAPIError(
|
|
121
|
+
"No se pueden proporcionar 'reference' y 'file' simultáneamente.",
|
|
122
|
+
400,
|
|
123
|
+
"INVALID_PARAMETER_FORMAT"
|
|
124
|
+
);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (!validatedSignerData.reference && !validatedSignerData.file) {
|
|
78
128
|
throw new ApacuanaAPIError(
|
|
79
|
-
|
|
129
|
+
"Se debe proporcionar un campo 'reference' o 'file' válido.",
|
|
80
130
|
400,
|
|
81
131
|
"INVALID_PARAMETER_FORMAT"
|
|
82
132
|
);
|
|
83
133
|
}
|
|
84
134
|
|
|
85
135
|
const validDocTypes = ["V", "P", "E"];
|
|
86
|
-
if (
|
|
136
|
+
if (
|
|
137
|
+
!validatedSignerData.typedoc ||
|
|
138
|
+
!validDocTypes.includes(validatedSignerData.typedoc)
|
|
139
|
+
) {
|
|
87
140
|
throw new ApacuanaAPIError(
|
|
88
141
|
'El campo "typedoc" es requerido y debe ser uno de los siguientes valores: V, P, E.',
|
|
89
142
|
400,
|
|
@@ -91,7 +144,7 @@ const validateOnBoardingSignerData = (signerData) => {
|
|
|
91
144
|
);
|
|
92
145
|
}
|
|
93
146
|
|
|
94
|
-
if (!
|
|
147
|
+
if (!validatedSignerData.doc || typeof validatedSignerData.doc !== "string") {
|
|
95
148
|
throw new ApacuanaAPIError(
|
|
96
149
|
'El campo "doc" es requerido y debe ser una cadena de texto.',
|
|
97
150
|
400,
|
|
@@ -100,8 +153,8 @@ const validateOnBoardingSignerData = (signerData) => {
|
|
|
100
153
|
}
|
|
101
154
|
|
|
102
155
|
if (
|
|
103
|
-
!Array.isArray(
|
|
104
|
-
|
|
156
|
+
!Array.isArray(validatedSignerData.signature) ||
|
|
157
|
+
validatedSignerData.signature.length === 0
|
|
105
158
|
) {
|
|
106
159
|
throw new ApacuanaAPIError(
|
|
107
160
|
'El campo "signature" es requerido y debe ser un array no vacío.',
|
|
@@ -110,7 +163,7 @@ const validateOnBoardingSignerData = (signerData) => {
|
|
|
110
163
|
);
|
|
111
164
|
}
|
|
112
165
|
|
|
113
|
-
|
|
166
|
+
validatedSignerData.signature.forEach((sig, index) => {
|
|
114
167
|
if (!Number.isInteger(sig.page) || sig.page < 1) {
|
|
115
168
|
throw new ApacuanaAPIError(
|
|
116
169
|
`La página de la firma ${
|
|
@@ -141,6 +194,19 @@ const validateOnBoardingSignerData = (signerData) => {
|
|
|
141
194
|
);
|
|
142
195
|
}
|
|
143
196
|
});
|
|
197
|
+
|
|
198
|
+
const formData = new FormData();
|
|
199
|
+
Object.keys(validatedSignerData).forEach((key) => {
|
|
200
|
+
if (key === "signature") {
|
|
201
|
+
formData.append(key, JSON.stringify(validatedSignerData[key]));
|
|
202
|
+
} else if (key === "file") {
|
|
203
|
+
formData.append("document", validatedSignerData[key]);
|
|
204
|
+
} else if (validatedSignerData[key] !== undefined) {
|
|
205
|
+
formData.append(key, validatedSignerData[key]);
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
return formData;
|
|
144
210
|
};
|
|
145
211
|
|
|
146
212
|
const validateCsr = (encryptedCSR) => {
|
|
@@ -243,6 +309,26 @@ const validateOnBoardingSignDocumentData = (signData) => {
|
|
|
243
309
|
"INVALID_PARAMETER"
|
|
244
310
|
);
|
|
245
311
|
}
|
|
312
|
+
|
|
313
|
+
const formData = new FormData();
|
|
314
|
+
formData.append(
|
|
315
|
+
"positions",
|
|
316
|
+
JSON.stringify(
|
|
317
|
+
signature.positions.map((p) => ({
|
|
318
|
+
x: p.x,
|
|
319
|
+
y: p.y,
|
|
320
|
+
page: p.page,
|
|
321
|
+
status: 1,
|
|
322
|
+
}))
|
|
323
|
+
)
|
|
324
|
+
);
|
|
325
|
+
formData.append("publickey", cert);
|
|
326
|
+
formData.append("signeddigest", signedDigest);
|
|
327
|
+
if (signData.document && signData.document instanceof File) {
|
|
328
|
+
formData.append("document", signData.document);
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
return formData;
|
|
246
332
|
};
|
|
247
333
|
|
|
248
334
|
export default {
|
|
@@ -255,4 +341,5 @@ export default {
|
|
|
255
341
|
validateGetDocsData,
|
|
256
342
|
validateGetDigestData,
|
|
257
343
|
validateOnBoardingSignDocumentData,
|
|
344
|
+
createPayloadGetDigest,
|
|
258
345
|
};
|
package/src/utils/httpClient.js
CHANGED
|
@@ -129,18 +129,23 @@ export const httpRequest = async (path, data = {}, method = "POST") => {
|
|
|
129
129
|
let dataToSend;
|
|
130
130
|
const requestConfig = {};
|
|
131
131
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
);
|
|
135
|
-
if (hasFile) {
|
|
136
|
-
const formData = new FormData();
|
|
137
|
-
Object.keys(data).forEach((key) => {
|
|
138
|
-
formData.append(key, data[key]);
|
|
139
|
-
});
|
|
140
|
-
dataToSend = formData;
|
|
132
|
+
if (typeof FormData !== "undefined" && data instanceof FormData) {
|
|
133
|
+
dataToSend = data;
|
|
141
134
|
} else {
|
|
142
|
-
|
|
135
|
+
const hasFile = Object.values(data).some(
|
|
136
|
+
(value) => typeof File !== "undefined" && value instanceof File
|
|
137
|
+
);
|
|
138
|
+
if (hasFile) {
|
|
139
|
+
const formData = new FormData();
|
|
140
|
+
Object.keys(data).forEach((key) => {
|
|
141
|
+
formData.append(key, data[key]);
|
|
142
|
+
});
|
|
143
|
+
dataToSend = formData;
|
|
144
|
+
} else {
|
|
145
|
+
dataToSend = { ...data };
|
|
146
|
+
}
|
|
143
147
|
}
|
|
148
|
+
|
|
144
149
|
try {
|
|
145
150
|
let response;
|
|
146
151
|
switch (method.toUpperCase()) {
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import
|
|
1
|
+
import {
|
|
2
|
+
createFaceLivenessSession,
|
|
3
|
+
validateFaceLiveness,
|
|
4
|
+
} from "../../src/api/faceLiveness";
|
|
2
5
|
import { httpRequest } from "../../src/utils/httpClient";
|
|
3
|
-
import { getConfig } from "../../src/config";
|
|
4
|
-
import { ApacuanaAPIError } from "../../src/errors";
|
|
5
6
|
import ApacuanaSuccess from "../../src/success";
|
|
7
|
+
import { setConfig, getConfig } from "../../src/config";
|
|
8
|
+
import { ApacuanaAPIError } from "../../src/errors";
|
|
6
9
|
import { INTEGRATION_TYPE } from "../../src/utils/constant";
|
|
7
10
|
|
|
8
11
|
jest.mock("../../src/utils/httpClient", () => ({
|
|
@@ -11,6 +14,7 @@ jest.mock("../../src/utils/httpClient", () => ({
|
|
|
11
14
|
|
|
12
15
|
jest.mock("../../src/config", () => ({
|
|
13
16
|
getConfig: jest.fn(),
|
|
17
|
+
setConfig: jest.fn(),
|
|
14
18
|
}));
|
|
15
19
|
|
|
16
20
|
describe("FaceLiveness API", () => {
|
|
@@ -21,23 +25,25 @@ describe("FaceLiveness API", () => {
|
|
|
21
25
|
|
|
22
26
|
describe("createFaceLivenessSession", () => {
|
|
23
27
|
it("should create a session for ONBOARDING integration", async () => {
|
|
24
|
-
|
|
28
|
+
const mockSessionId = "session-onboarding-123";
|
|
29
|
+
httpRequest.mockResolvedValue({ sessionid: mockSessionId });
|
|
30
|
+
setConfig({ onboardingId: "some-onboarding-id" });
|
|
25
31
|
|
|
26
|
-
const result = await
|
|
32
|
+
const result = await createFaceLivenessSession();
|
|
27
33
|
|
|
28
|
-
expect(result).toBeInstanceOf(ApacuanaSuccess);
|
|
29
|
-
expect(result.data).toEqual({ sessionId: "test-session-id" });
|
|
30
34
|
expect(httpRequest).toHaveBeenCalledWith(
|
|
31
35
|
"services/api/faceliveness/create",
|
|
32
36
|
{},
|
|
33
37
|
"POST"
|
|
34
38
|
);
|
|
39
|
+
expect(result).toBeInstanceOf(ApacuanaSuccess);
|
|
40
|
+
expect(result.data).toEqual({ sessionId: mockSessionId });
|
|
35
41
|
});
|
|
36
42
|
|
|
37
|
-
it("should throw an error if
|
|
43
|
+
it("should throw an error if session ID is missing for ONBOARDING", async () => {
|
|
38
44
|
httpRequest.mockResolvedValue({}); // No sessionId
|
|
39
45
|
|
|
40
|
-
await expect(
|
|
46
|
+
await expect(createFaceLivenessSession()).rejects.toThrow(
|
|
41
47
|
new ApacuanaAPIError(
|
|
42
48
|
"The API response does not contain the session ID.",
|
|
43
49
|
undefined,
|
|
@@ -51,7 +57,7 @@ describe("FaceLiveness API", () => {
|
|
|
51
57
|
integrationType: INTEGRATION_TYPE.ONPREMISE,
|
|
52
58
|
});
|
|
53
59
|
|
|
54
|
-
await expect(
|
|
60
|
+
await expect(createFaceLivenessSession()).rejects.toThrow(
|
|
55
61
|
new ApacuanaAPIError(
|
|
56
62
|
"Creating a Face Liveness session is not supported for integration type: ONPREMISE",
|
|
57
63
|
501,
|
|
@@ -63,7 +69,7 @@ describe("FaceLiveness API", () => {
|
|
|
63
69
|
it("should throw an UNSUPPORTED_INTEGRATION_TYPE error for unsupported integration types", async () => {
|
|
64
70
|
getConfig.mockReturnValue({ integrationType: "unsupported-type" });
|
|
65
71
|
|
|
66
|
-
await expect(
|
|
72
|
+
await expect(createFaceLivenessSession()).rejects.toThrow(
|
|
67
73
|
new ApacuanaAPIError(
|
|
68
74
|
"Unsupported integration type: unsupported-type",
|
|
69
75
|
400,
|
|
@@ -76,16 +82,14 @@ describe("FaceLiveness API", () => {
|
|
|
76
82
|
const apiError = new ApacuanaAPIError("API Error", 500, "API_ERROR");
|
|
77
83
|
httpRequest.mockRejectedValue(apiError);
|
|
78
84
|
|
|
79
|
-
await expect(
|
|
80
|
-
apiError
|
|
81
|
-
);
|
|
85
|
+
await expect(createFaceLivenessSession()).rejects.toThrow(apiError);
|
|
82
86
|
});
|
|
83
87
|
|
|
84
88
|
it("should throw a generic error for other failures during session creation", async () => {
|
|
85
89
|
const genericError = new Error("Network Error");
|
|
86
90
|
httpRequest.mockRejectedValue(genericError);
|
|
87
91
|
|
|
88
|
-
await expect(
|
|
92
|
+
await expect(createFaceLivenessSession()).rejects.toThrow(
|
|
89
93
|
`Failed to create Face Liveness session: ${genericError.message}`
|
|
90
94
|
);
|
|
91
95
|
});
|
|
@@ -95,7 +99,7 @@ describe("FaceLiveness API", () => {
|
|
|
95
99
|
const sessionId = "test-session-id";
|
|
96
100
|
|
|
97
101
|
it("should throw an error if sessionId is not provided", async () => {
|
|
98
|
-
await expect(
|
|
102
|
+
await expect(validateFaceLiveness({})).rejects.toThrow(
|
|
99
103
|
new ApacuanaAPIError(
|
|
100
104
|
"sessionId is a required parameter.",
|
|
101
105
|
400,
|
|
@@ -107,7 +111,7 @@ describe("FaceLiveness API", () => {
|
|
|
107
111
|
it("should return 'verified' on status 200", async () => {
|
|
108
112
|
httpRequest.mockResolvedValue({ someData: "data" });
|
|
109
113
|
|
|
110
|
-
const result = await
|
|
114
|
+
const result = await validateFaceLiveness({ sessionId });
|
|
111
115
|
|
|
112
116
|
expect(result).toBeInstanceOf(ApacuanaSuccess);
|
|
113
117
|
expect(result.data).toEqual({ status: "verified", someData: "data" });
|
|
@@ -126,14 +130,10 @@ describe("FaceLiveness API", () => {
|
|
|
126
130
|
])(
|
|
127
131
|
"should return status '%s' for statusCode %i",
|
|
128
132
|
async (statusCode, status) => {
|
|
129
|
-
const apiError = new ApacuanaAPIError(
|
|
130
|
-
"Error",
|
|
131
|
-
statusCode,
|
|
132
|
-
"API_ERROR"
|
|
133
|
-
);
|
|
133
|
+
const apiError = new ApacuanaAPIError("Error", statusCode, "API_ERROR");
|
|
134
134
|
httpRequest.mockRejectedValue(apiError);
|
|
135
135
|
|
|
136
|
-
const result = await
|
|
136
|
+
const result = await validateFaceLiveness({ sessionId });
|
|
137
137
|
|
|
138
138
|
expect(result).toBeInstanceOf(ApacuanaSuccess);
|
|
139
139
|
expect(result.data).toEqual({ status });
|
|
@@ -148,9 +148,9 @@ describe("FaceLiveness API", () => {
|
|
|
148
148
|
);
|
|
149
149
|
httpRequest.mockRejectedValue(apiError);
|
|
150
150
|
|
|
151
|
-
await expect(
|
|
152
|
-
|
|
153
|
-
)
|
|
151
|
+
await expect(validateFaceLiveness({ sessionId })).rejects.toThrow(
|
|
152
|
+
apiError
|
|
153
|
+
);
|
|
154
154
|
});
|
|
155
155
|
|
|
156
156
|
it("should throw a NOT_IMPLEMENTED error for ONPREMISE integration", async () => {
|
|
@@ -158,9 +158,7 @@ describe("FaceLiveness API", () => {
|
|
|
158
158
|
integrationType: INTEGRATION_TYPE.ONPREMISE,
|
|
159
159
|
});
|
|
160
160
|
|
|
161
|
-
await expect(
|
|
162
|
-
faceLiveness.validateFaceLiveness({ sessionId })
|
|
163
|
-
).rejects.toThrow(
|
|
161
|
+
await expect(validateFaceLiveness({ sessionId })).rejects.toThrow(
|
|
164
162
|
new ApacuanaAPIError(
|
|
165
163
|
"Validating a Face Liveness session is not supported for integration type: ONPREMISE",
|
|
166
164
|
501,
|
|
@@ -169,4 +167,4 @@ describe("FaceLiveness API", () => {
|
|
|
169
167
|
);
|
|
170
168
|
});
|
|
171
169
|
});
|
|
172
|
-
});
|
|
170
|
+
});
|
|
@@ -35,7 +35,7 @@ describe("Revocations API", () => {
|
|
|
35
35
|
const result = await requestRevocation(params);
|
|
36
36
|
|
|
37
37
|
expect(httpRequest).toHaveBeenCalledWith(
|
|
38
|
-
"services/api/
|
|
38
|
+
"services/api/onboardingclient/requestcert",
|
|
39
39
|
params,
|
|
40
40
|
"POST"
|
|
41
41
|
);
|
|
@@ -64,18 +64,18 @@ describe("Revocations API", () => {
|
|
|
64
64
|
|
|
65
65
|
describe("getRevocationReasons", () => {
|
|
66
66
|
it("should make a GET request and return the reasons for ONBOARDING", async () => {
|
|
67
|
-
const mockReasons = [{ code:
|
|
67
|
+
const mockReasons = [{ code: "01", description: "Test Reason" }];
|
|
68
68
|
httpRequest.mockResolvedValue({ records: mockReasons });
|
|
69
69
|
|
|
70
70
|
const result = await getRevocationReasons();
|
|
71
71
|
|
|
72
72
|
expect(httpRequest).toHaveBeenCalledWith(
|
|
73
|
-
"
|
|
73
|
+
"config/api/revocation/reasonsonboarding",
|
|
74
74
|
{},
|
|
75
75
|
"GET"
|
|
76
76
|
);
|
|
77
77
|
expect(result).toBeInstanceOf(ApacuanaSuccess);
|
|
78
|
-
expect(result.data).toEqual(mockReasons);
|
|
78
|
+
expect(result.data).toEqual({ reasons: mockReasons });
|
|
79
79
|
});
|
|
80
80
|
|
|
81
81
|
it("should throw an error if the API response does not contain 'records'", async () => {
|
|
@@ -24,9 +24,32 @@ jest.mock("../../src/utils/helpers", () => ({
|
|
|
24
24
|
validateGetDocsData: jest.fn(),
|
|
25
25
|
validateGetDigestData: jest.fn(),
|
|
26
26
|
validateOnBoardingSignDocumentData: jest.fn(),
|
|
27
|
+
createPayloadGetDigest: jest.fn(),
|
|
27
28
|
}));
|
|
28
29
|
|
|
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
|
+
|
|
30
53
|
afterEach(() => {
|
|
31
54
|
jest.resetAllMocks();
|
|
32
55
|
});
|
|
@@ -37,6 +60,12 @@ describe("API - Signatures", () => {
|
|
|
37
60
|
integrationType: INTEGRATION_TYPE.ONBOARDING,
|
|
38
61
|
});
|
|
39
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);
|
|
40
69
|
httpRequest.mockResolvedValue({ success: true });
|
|
41
70
|
|
|
42
71
|
await addSigner(signerData);
|
|
@@ -45,8 +74,8 @@ describe("API - Signatures", () => {
|
|
|
45
74
|
signerData
|
|
46
75
|
);
|
|
47
76
|
expect(httpRequest).toHaveBeenCalledWith(
|
|
48
|
-
"services/api/documents/
|
|
49
|
-
|
|
77
|
+
"services/api/documents/signingsdk",
|
|
78
|
+
formData,
|
|
50
79
|
"POST"
|
|
51
80
|
);
|
|
52
81
|
});
|
|
@@ -177,12 +206,17 @@ describe("API - Signatures", () => {
|
|
|
177
206
|
const mockResponse = { data: { digest: "test-digest" } };
|
|
178
207
|
httpRequest.mockResolvedValue(mockResponse);
|
|
179
208
|
|
|
209
|
+
const expectedFormData = new FormData();
|
|
210
|
+
expectedFormData.append("publickey", "test-cert");
|
|
211
|
+
helpers.createPayloadGetDigest.mockReturnValue(expectedFormData);
|
|
212
|
+
|
|
180
213
|
const result = await getDigest(signData);
|
|
181
214
|
|
|
182
215
|
expect(helpers.validateGetDigestData).toHaveBeenCalledWith(signData);
|
|
216
|
+
expect(helpers.createPayloadGetDigest).toHaveBeenCalledWith(signData);
|
|
183
217
|
expect(httpRequest).toHaveBeenCalledWith(
|
|
184
218
|
`services/api/documents/getdigest/${signData.signatureId}`,
|
|
185
|
-
|
|
219
|
+
expectedFormData,
|
|
186
220
|
"POST"
|
|
187
221
|
);
|
|
188
222
|
expect(result).toBeInstanceOf(ApacuanaSuccess);
|
|
@@ -243,20 +277,33 @@ describe("API - Signatures", () => {
|
|
|
243
277
|
const mockResponse = { success: true };
|
|
244
278
|
httpRequest.mockResolvedValue(mockResponse);
|
|
245
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
|
+
|
|
246
299
|
const result = await signDocument(signData);
|
|
247
300
|
|
|
248
|
-
expect(
|
|
249
|
-
|
|
250
|
-
)
|
|
301
|
+
expect(helpers.validateOnBoardingSignDocumentData).toHaveBeenCalledWith(
|
|
302
|
+
signData
|
|
303
|
+
);
|
|
251
304
|
expect(httpRequest).toHaveBeenCalledWith(
|
|
252
305
|
`services/api/documents/sign/${signData.signature.id}`,
|
|
253
|
-
|
|
254
|
-
positions: JSON.stringify([
|
|
255
|
-
{ x: 0.1, y: 0.2, page: 1, status: 1 },
|
|
256
|
-
]),
|
|
257
|
-
publickey: signData.cert,
|
|
258
|
-
signeddigest: signData.signedDigest,
|
|
259
|
-
},
|
|
306
|
+
expectedFormData,
|
|
260
307
|
"PUT"
|
|
261
308
|
);
|
|
262
309
|
expect(result).toBeInstanceOf(ApacuanaSuccess);
|
|
@@ -306,10 +353,18 @@ describe("API - Signatures", () => {
|
|
|
306
353
|
|
|
307
354
|
it("should throw an error if data or data.file is not provided", async () => {
|
|
308
355
|
await expect(uploadSignatureVariant(null)).rejects.toThrow(
|
|
309
|
-
new ApacuanaAPIError(
|
|
356
|
+
new ApacuanaAPIError(
|
|
357
|
+
"El parámetro 'file' es requerido.",
|
|
358
|
+
400,
|
|
359
|
+
"INVALID_PARAMETER"
|
|
360
|
+
)
|
|
310
361
|
);
|
|
311
362
|
await expect(uploadSignatureVariant({})).rejects.toThrow(
|
|
312
|
-
new ApacuanaAPIError(
|
|
363
|
+
new ApacuanaAPIError(
|
|
364
|
+
"El parámetro 'file' es requerido.",
|
|
365
|
+
400,
|
|
366
|
+
"INVALID_PARAMETER"
|
|
367
|
+
)
|
|
313
368
|
);
|
|
314
369
|
});
|
|
315
370
|
|
|
@@ -325,7 +380,9 @@ describe("API - Signatures", () => {
|
|
|
325
380
|
|
|
326
381
|
it("should throw an error if file is not a PNG", async () => {
|
|
327
382
|
const invalidFile = new File([], "test.txt", { type: "text/plain" });
|
|
328
|
-
await expect(
|
|
383
|
+
await expect(
|
|
384
|
+
uploadSignatureVariant({ file: invalidFile })
|
|
385
|
+
).rejects.toThrow(
|
|
329
386
|
new ApacuanaAPIError(
|
|
330
387
|
"El archivo debe ser de tipo PNG (image/png).",
|
|
331
388
|
400,
|