@zerosls/clm-sdk 1.0.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/.docs/publicacion-npm.md +111 -0
- package/.env.example +14 -0
- package/.gitlab-ci.yml +23 -0
- package/README.md +202 -0
- package/dist/config/config.d.ts +3 -0
- package/dist/config/config.js +21 -0
- package/dist/core/api-client.d.ts +27 -0
- package/dist/core/api-client.js +183 -0
- package/dist/core/api-error.d.ts +15 -0
- package/dist/core/api-error.js +46 -0
- package/dist/core/event-emitter.d.ts +11 -0
- package/dist/core/event-emitter.js +32 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.js +59 -0
- package/dist/modules/legacy/areas/areas-api.d.ts +34 -0
- package/dist/modules/legacy/areas/areas-api.js +44 -0
- package/dist/modules/legacy/areas/types.d.ts +37 -0
- package/dist/modules/legacy/areas/types.js +1 -0
- package/dist/modules/legacy/classificationtypes/classificationtypes-api.d.ts +34 -0
- package/dist/modules/legacy/classificationtypes/classificationtypes-api.js +46 -0
- package/dist/modules/legacy/classificationtypes/types.d.ts +41 -0
- package/dist/modules/legacy/classificationtypes/types.js +1 -0
- package/dist/modules/v1/auth/auth-api.d.ts +17 -0
- package/dist/modules/v1/auth/auth-api.js +63 -0
- package/dist/modules/v1/auth/types.d.ts +18 -0
- package/dist/modules/v1/auth/types.js +1 -0
- package/dist/modules/v1/main/main-api.d.ts +11 -0
- package/dist/modules/v1/main/main-api.js +14 -0
- package/dist/modules/v1/main/types.d.ts +3 -0
- package/dist/modules/v1/main/types.js +1 -0
- package/dist/modules/v1/notifications/notification-api.d.ts +16 -0
- package/dist/modules/v1/notifications/notification-api.js +26 -0
- package/dist/modules/v1/notifications/types.d.ts +53 -0
- package/dist/modules/v1/notifications/types.js +1 -0
- package/dist/modules/v1/users/types.d.ts +64 -0
- package/dist/modules/v1/users/types.js +1 -0
- package/dist/modules/v1/users/users-api.d.ts +81 -0
- package/dist/modules/v1/users/users-api.js +113 -0
- package/dist/types/common.d.ts +18 -0
- package/dist/types/common.js +1 -0
- package/dist/types/sdk.d.ts +42 -0
- package/dist/types/sdk.js +11 -0
- package/dist/utils/cache.d.ts +10 -0
- package/dist/utils/cache.js +43 -0
- package/dist/utils/http.d.ts +5 -0
- package/dist/utils/http.js +56 -0
- package/package.json +38 -0
- package/src/config/config.ts +24 -0
- package/src/core/api-client.ts +272 -0
- package/src/core/api-error.ts +54 -0
- package/src/core/event-emitter.ts +43 -0
- package/src/index.ts +89 -0
- package/src/modules/legacy/areas/areas-api.ts +73 -0
- package/src/modules/legacy/areas/types.ts +49 -0
- package/src/modules/legacy/classificationtypes/classificationtypes-api.ts +80 -0
- package/src/modules/legacy/classificationtypes/types.ts +52 -0
- package/src/modules/v1/auth/auth-api.ts +75 -0
- package/src/modules/v1/auth/types.ts +20 -0
- package/src/modules/v1/main/main-api.ts +20 -0
- package/src/modules/v1/main/types.ts +3 -0
- package/src/modules/v1/notifications/notification-api.ts +55 -0
- package/src/modules/v1/notifications/types.ts +58 -0
- package/src/modules/v1/users/types.ts +83 -0
- package/src/modules/v1/users/users-api.ts +148 -0
- package/src/types/common.ts +22 -0
- package/src/types/sdk.ts +38 -0
- package/src/utils/cache.ts +58 -0
- package/src/utils/http.ts +77 -0
- package/tests/integration/legacy/auth-areas.test.ts +115 -0
- package/tests/integration/legacy/auth-classification-types.test.ts +80 -0
- package/tests/integration/v1/auth-logs.test.ts +145 -0
- package/tests/integration/v1/auth-users.test.ts +189 -0
- package/tests/modules/legacy/areas/areas-api.test.ts +232 -0
- package/tests/modules/legacy/classification-types/classification-types-api.test.ts +100 -0
- package/tests/modules/v1/auth/auth-api.test.ts +134 -0
- package/tests/modules/v1/users/users-api.test.ts +176 -0
- package/tests/setup.ts +12 -0
- package/tests/utils/test-utils.ts +453 -0
- package/tsconfig.json +16 -0
- package/tsconfig.test.json +13 -0
- package/vitest.config.ts +16 -0
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
// tests/modules/areas/areas-api.test.ts
|
|
2
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
3
|
+
import { ClmSdk } from '../../../../src/index';
|
|
4
|
+
import { setupFetchMock, AUTH_TEST_DATA, AREAS_TEST_DATA } from '../../../utils/test-utils';
|
|
5
|
+
|
|
6
|
+
describe('AreasApi', () => {
|
|
7
|
+
let sdk: ClmSdk;
|
|
8
|
+
const TOKEN = AUTH_TEST_DATA.loginToken;
|
|
9
|
+
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
sdk = new ClmSdk({
|
|
12
|
+
baseUrl: 'http://216.250.117.119/ZeroServicesQA/api/v1',
|
|
13
|
+
organization: 'default-org',
|
|
14
|
+
token: TOKEN
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
describe('getAreas', () => {
|
|
19
|
+
it('debe obtener todas las áreas correctamente', async () => {
|
|
20
|
+
setupFetchMock([
|
|
21
|
+
{
|
|
22
|
+
url: '/catalog/areas',
|
|
23
|
+
method: 'GET',
|
|
24
|
+
response: {
|
|
25
|
+
status: 200,
|
|
26
|
+
data: AREAS_TEST_DATA.areasList
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
]);
|
|
30
|
+
|
|
31
|
+
const result = await sdk.areas.getAreas();
|
|
32
|
+
|
|
33
|
+
expect(global.fetch).toHaveBeenCalledTimes(1);
|
|
34
|
+
|
|
35
|
+
const calledUrl = (global.fetch as any).mock.calls[0][0];
|
|
36
|
+
expect(calledUrl).toBe('http://216.250.117.119/ZeroServicesQA/api/v1/catalog/areas');
|
|
37
|
+
|
|
38
|
+
const options = (global.fetch as any).mock.calls[0][1];
|
|
39
|
+
expect(options.method).toBe('GET');
|
|
40
|
+
|
|
41
|
+
expect(result).toEqual(AREAS_TEST_DATA.areasList);
|
|
42
|
+
expect(result.dataResult.length).toBeGreaterThan(0);
|
|
43
|
+
expect(result.statusResponse.success).toBe(true);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('debe manejar respuestas vacías', async () => {
|
|
47
|
+
setupFetchMock([
|
|
48
|
+
{
|
|
49
|
+
url: '/catalog/areas',
|
|
50
|
+
method: 'GET',
|
|
51
|
+
response: {
|
|
52
|
+
status: 200,
|
|
53
|
+
data: {
|
|
54
|
+
dataResult: [],
|
|
55
|
+
statusResponse: {
|
|
56
|
+
code: 200,
|
|
57
|
+
success: true,
|
|
58
|
+
message: 'success'
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
]);
|
|
64
|
+
|
|
65
|
+
const result = await sdk.areas.getAreas();
|
|
66
|
+
|
|
67
|
+
expect(result.dataResult).toEqual([]);
|
|
68
|
+
expect(result.statusResponse.success).toBe(true);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('debe recibir respuesta de error del servidor', async () => {
|
|
72
|
+
setupFetchMock([
|
|
73
|
+
{
|
|
74
|
+
url: '/catalog/areas',
|
|
75
|
+
method: 'GET',
|
|
76
|
+
response: {
|
|
77
|
+
status: 500,
|
|
78
|
+
data: {
|
|
79
|
+
dataResult: [],
|
|
80
|
+
statusResponse: {
|
|
81
|
+
code: 500,
|
|
82
|
+
success: false,
|
|
83
|
+
message: 'Internal server error'
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
]);
|
|
89
|
+
|
|
90
|
+
const result = await sdk.areas.getAreas();
|
|
91
|
+
|
|
92
|
+
// Verificar que la respuesta contiene el error
|
|
93
|
+
expect(result.statusResponse.success).toBe(false);
|
|
94
|
+
expect(result.statusResponse.code).toBe(500);
|
|
95
|
+
expect(result.statusResponse.message).toContain('error');
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
describe('createArea', () => {
|
|
100
|
+
it('debe crear un área correctamente', async () => {
|
|
101
|
+
setupFetchMock([
|
|
102
|
+
{
|
|
103
|
+
url: '/catalog/areas',
|
|
104
|
+
method: 'POST',
|
|
105
|
+
response: {
|
|
106
|
+
status: 200,
|
|
107
|
+
data: AREAS_TEST_DATA.createAreaResponse
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
]);
|
|
111
|
+
|
|
112
|
+
const result = await sdk.areas.createArea(AREAS_TEST_DATA.newAreaRequest);
|
|
113
|
+
|
|
114
|
+
const options = (global.fetch as any).mock.calls[0][1];
|
|
115
|
+
expect(options.method).toBe('POST');
|
|
116
|
+
|
|
117
|
+
const body = JSON.parse(options.body);
|
|
118
|
+
expect(body.name).toBe('Testing QA');
|
|
119
|
+
expect(body.description).toBe('Área de pruebas y aseguramiento de calidad');
|
|
120
|
+
|
|
121
|
+
expect(result.statusResponse.success).toBe(true);
|
|
122
|
+
expect(result.statusResponse.code).toBe(200);
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
it('debe enviar todos los campos requeridos', async () => {
|
|
126
|
+
setupFetchMock([
|
|
127
|
+
{
|
|
128
|
+
url: '/catalog/areas',
|
|
129
|
+
method: 'POST',
|
|
130
|
+
response: {
|
|
131
|
+
status: 200,
|
|
132
|
+
data: AREAS_TEST_DATA.createAreaResponse
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
]);
|
|
136
|
+
|
|
137
|
+
await sdk.areas.createArea(AREAS_TEST_DATA.newAreaRequest);
|
|
138
|
+
|
|
139
|
+
const options = (global.fetch as any).mock.calls[0][1];
|
|
140
|
+
const body = JSON.parse(options.body);
|
|
141
|
+
|
|
142
|
+
expect(body).toHaveProperty('createdBy');
|
|
143
|
+
expect(body).toHaveProperty('createdByName');
|
|
144
|
+
expect(body).toHaveProperty('createdOn');
|
|
145
|
+
expect(body).toHaveProperty('lastModBy');
|
|
146
|
+
expect(body).toHaveProperty('lastModByName');
|
|
147
|
+
expect(body).toHaveProperty('lastModOn');
|
|
148
|
+
expect(body).toHaveProperty('name');
|
|
149
|
+
expect(body).toHaveProperty('description');
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
describe('updateArea', () => {
|
|
154
|
+
it('debe actualizar un área correctamente', async () => {
|
|
155
|
+
setupFetchMock([
|
|
156
|
+
{
|
|
157
|
+
url: '/catalog/areas',
|
|
158
|
+
method: 'PATCH',
|
|
159
|
+
response: {
|
|
160
|
+
status: 200,
|
|
161
|
+
data: AREAS_TEST_DATA.updateAreaResponse
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
]);
|
|
165
|
+
|
|
166
|
+
const result = await sdk.areas.updateArea(AREAS_TEST_DATA.updateAreaRequest);
|
|
167
|
+
|
|
168
|
+
const options = (global.fetch as any).mock.calls[0][1];
|
|
169
|
+
expect(options.method).toBe('PATCH');
|
|
170
|
+
|
|
171
|
+
const body = JSON.parse(options.body);
|
|
172
|
+
expect(body.id).toBe(26);
|
|
173
|
+
expect(body.name).toBe('Testing QA - Actualizado');
|
|
174
|
+
|
|
175
|
+
expect(result.statusResponse.success).toBe(true);
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
describe('deleteArea', () => {
|
|
180
|
+
it('debe eliminar un área correctamente', async () => {
|
|
181
|
+
setupFetchMock([
|
|
182
|
+
{
|
|
183
|
+
url: '/catalog/areas',
|
|
184
|
+
method: 'DELETE',
|
|
185
|
+
response: {
|
|
186
|
+
status: 200,
|
|
187
|
+
data: AREAS_TEST_DATA.deleteAreaResponse
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
]);
|
|
191
|
+
|
|
192
|
+
const result = await sdk.areas.deleteArea({ id: 26 });
|
|
193
|
+
|
|
194
|
+
const options = (global.fetch as any).mock.calls[0][1];
|
|
195
|
+
const calledUrl = (global.fetch as any).mock.calls[0][0];
|
|
196
|
+
|
|
197
|
+
expect(options.method).toBe('DELETE');
|
|
198
|
+
|
|
199
|
+
// Tu ApiClient envía el ID como query param
|
|
200
|
+
expect(calledUrl).toContain('id=26');
|
|
201
|
+
|
|
202
|
+
expect(result.statusResponse.success).toBe(true);
|
|
203
|
+
});
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
describe('generateAuditData', () => {
|
|
207
|
+
it('debe generar datos de auditoría correctamente', () => {
|
|
208
|
+
const auditData = sdk.areas.generateAuditData('USR001', 'Juan Pérez');
|
|
209
|
+
|
|
210
|
+
expect(auditData).toHaveProperty('createdBy', 'USR001');
|
|
211
|
+
expect(auditData).toHaveProperty('createdByName', 'Juan Pérez');
|
|
212
|
+
expect(auditData).toHaveProperty('createdOn');
|
|
213
|
+
expect(auditData).toHaveProperty('lastModBy', 'USR001');
|
|
214
|
+
expect(auditData).toHaveProperty('lastModByName', 'Juan Pérez');
|
|
215
|
+
expect(auditData).toHaveProperty('lastModOn');
|
|
216
|
+
|
|
217
|
+
expect(new Date(auditData.createdOn).toISOString()).toBe(auditData.createdOn);
|
|
218
|
+
expect(new Date(auditData.lastModOn).toISOString()).toBe(auditData.lastModOn);
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it('debe generar fechas actuales', () => {
|
|
222
|
+
const before = new Date().getTime();
|
|
223
|
+
const auditData = sdk.areas.generateAuditData('USR001', 'Test User');
|
|
224
|
+
const after = new Date().getTime();
|
|
225
|
+
|
|
226
|
+
const createdTime = new Date(auditData.createdOn).getTime();
|
|
227
|
+
|
|
228
|
+
expect(createdTime).toBeGreaterThanOrEqual(before);
|
|
229
|
+
expect(createdTime).toBeLessThanOrEqual(after);
|
|
230
|
+
});
|
|
231
|
+
});
|
|
232
|
+
});
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
+
import { ClmSdk } from '../../../../src/index';
|
|
3
|
+
import { setupFetchMock, AUTH_TEST_DATA, CLASSIFICATION_TYPES_TEST_DATA } from '../../../utils/test-utils';
|
|
4
|
+
|
|
5
|
+
describe('ClassificationTypesApi', () => {
|
|
6
|
+
let sdk: ClmSdk;
|
|
7
|
+
const TOKEN = AUTH_TEST_DATA.loginToken;
|
|
8
|
+
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
sdk = new ClmSdk({
|
|
11
|
+
baseUrl: 'http://216.250.117.119/ZeroServicesQA/api/v1',
|
|
12
|
+
organization: 'default-org',
|
|
13
|
+
token: TOKEN
|
|
14
|
+
});
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
describe('getClassificationTypes', () => {
|
|
18
|
+
it('debe obtener todos los tipos de clasificación', async () => {
|
|
19
|
+
setupFetchMock([
|
|
20
|
+
{
|
|
21
|
+
url: '/catalog/clasificationtype',
|
|
22
|
+
method: 'GET',
|
|
23
|
+
response: {
|
|
24
|
+
status: 200,
|
|
25
|
+
data: CLASSIFICATION_TYPES_TEST_DATA.classificationTypesList
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
]);
|
|
29
|
+
|
|
30
|
+
const result = await sdk.classificationTypes.getClassificationTypes();
|
|
31
|
+
|
|
32
|
+
expect(result.dataResult.length).toBeGreaterThan(0);
|
|
33
|
+
expect(result.statusResponse.success).toBe(true);
|
|
34
|
+
expect(result.dataResult[0]).toHaveProperty('id');
|
|
35
|
+
expect(result.dataResult[0]).toHaveProperty('name');
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
describe('createClassificationType', () => {
|
|
40
|
+
it('debe crear un tipo de clasificación correctamente', async () => {
|
|
41
|
+
setupFetchMock([
|
|
42
|
+
{
|
|
43
|
+
url: '/catalog/clasificationtype',
|
|
44
|
+
method: 'POST',
|
|
45
|
+
response: {
|
|
46
|
+
status: 200,
|
|
47
|
+
data: CLASSIFICATION_TYPES_TEST_DATA.createClassificationTypeResponse
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
]);
|
|
51
|
+
|
|
52
|
+
const result = await sdk.classificationTypes.createClassificationType(
|
|
53
|
+
CLASSIFICATION_TYPES_TEST_DATA.newClassificationTypeRequest
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
expect(result.statusResponse.success).toBe(true);
|
|
57
|
+
expect(result.dataResult?.name).toBe("Contrato de Prueba");
|
|
58
|
+
});
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
describe('updateClassificationType', () => {
|
|
62
|
+
it('debe actualizar un tipo de clasificación correctamente', async () => {
|
|
63
|
+
setupFetchMock([
|
|
64
|
+
{
|
|
65
|
+
url: '/catalog/clasificationtype',
|
|
66
|
+
method: 'PUT',
|
|
67
|
+
response: {
|
|
68
|
+
status: 200,
|
|
69
|
+
data: CLASSIFICATION_TYPES_TEST_DATA.updateClassificationTypeResponse
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
]);
|
|
73
|
+
|
|
74
|
+
const result = await sdk.classificationTypes.updateClassificationType(
|
|
75
|
+
CLASSIFICATION_TYPES_TEST_DATA.updateClassificationTypeRequest
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
expect(result.statusResponse.success).toBe(true);
|
|
79
|
+
});
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
describe('deleteClassificationType', () => {
|
|
83
|
+
it('debe eliminar un tipo de clasificación correctamente', async () => {
|
|
84
|
+
setupFetchMock([
|
|
85
|
+
{
|
|
86
|
+
url: '/catalog/clasificationtype',
|
|
87
|
+
method: 'DELETE',
|
|
88
|
+
response: {
|
|
89
|
+
status: 200,
|
|
90
|
+
data: CLASSIFICATION_TYPES_TEST_DATA.deleteClassificationTypeResponse
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
]);
|
|
94
|
+
|
|
95
|
+
const result = await sdk.classificationTypes.deleteClassificationType({ id: 20 });
|
|
96
|
+
|
|
97
|
+
expect(result.statusResponse.success).toBe(true);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
});
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { ClmSdk } from '../../../../src/index';
|
|
3
|
+
import { setupFetchMock, AUTH_TEST_DATA } from '../../../utils/test-utils';
|
|
4
|
+
|
|
5
|
+
describe('AuthApi', () => {
|
|
6
|
+
let sdk: ClmSdk;
|
|
7
|
+
|
|
8
|
+
beforeEach(() => {
|
|
9
|
+
// Crear una instancia nueva del SDK para cada prueba
|
|
10
|
+
sdk = new ClmSdk({
|
|
11
|
+
baseUrl: 'https://dev-api.zeroclm.io',
|
|
12
|
+
organization: 'default-org'
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
describe('login', () => {
|
|
17
|
+
it('debe autenticar correctamente con credenciales válidas', async () => {
|
|
18
|
+
// Configurar el mock de fetch para la petición de login
|
|
19
|
+
setupFetchMock([
|
|
20
|
+
{
|
|
21
|
+
url: '/auth/login',
|
|
22
|
+
method: 'GET',
|
|
23
|
+
response: {
|
|
24
|
+
status: 200,
|
|
25
|
+
data: AUTH_TEST_DATA.loginToken
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
]);
|
|
29
|
+
|
|
30
|
+
// Realizar login
|
|
31
|
+
const token = await sdk.auth.login({
|
|
32
|
+
email: 'test@example.com',
|
|
33
|
+
password: 'password123'
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// Verificar que se hizo la petición correcta
|
|
37
|
+
expect(global.fetch).toHaveBeenCalledTimes(1);
|
|
38
|
+
expect(global.fetch).toHaveBeenCalledWith(
|
|
39
|
+
'https://dev-api.zeroclm.io/auth/login',
|
|
40
|
+
expect.objectContaining({
|
|
41
|
+
method: 'GET',
|
|
42
|
+
headers: expect.any(Headers),
|
|
43
|
+
credentials: 'include'
|
|
44
|
+
})
|
|
45
|
+
);
|
|
46
|
+
|
|
47
|
+
// Verificar que el header de autorización usa Basic Auth
|
|
48
|
+
const headers = (global.fetch as any).mock.calls[0][1].headers;
|
|
49
|
+
expect(headers.get('Authorization')).toMatch(/^Basic /);
|
|
50
|
+
|
|
51
|
+
// Verificar que devolvió el token correcto
|
|
52
|
+
expect(token).toBe(AUTH_TEST_DATA.loginToken);
|
|
53
|
+
|
|
54
|
+
// Verificar que el token se guardó en el cliente
|
|
55
|
+
expect(sdk.auth.isAuthenticated()).toBe(true);
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('debe manejar errores de autenticación', async () => {
|
|
59
|
+
// Configurar mock para una respuesta de error
|
|
60
|
+
setupFetchMock([
|
|
61
|
+
{
|
|
62
|
+
url: '/auth/login',
|
|
63
|
+
method: 'GET',
|
|
64
|
+
response: {
|
|
65
|
+
status: 401,
|
|
66
|
+
data: {
|
|
67
|
+
statusCode: 401,
|
|
68
|
+
message: 'Invalid credentials',
|
|
69
|
+
error: 'Unauthorized'
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
]);
|
|
74
|
+
|
|
75
|
+
// Intentar login con credenciales incorrectas y esperar que falle
|
|
76
|
+
await expect(
|
|
77
|
+
sdk.auth.login({
|
|
78
|
+
email: 'wrong@example.com',
|
|
79
|
+
password: 'wrongpassword'
|
|
80
|
+
})
|
|
81
|
+
).rejects.toThrow('Invalid credentials');
|
|
82
|
+
|
|
83
|
+
// Verificar que el usuario no está autenticado después del error
|
|
84
|
+
expect(sdk.auth.isAuthenticated()).toBe(false);
|
|
85
|
+
});
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
describe('setToken', () => {
|
|
89
|
+
it('debe establecer el token correctamente', () => {
|
|
90
|
+
// Establecer el token
|
|
91
|
+
sdk.auth.setToken(AUTH_TEST_DATA.loginToken);
|
|
92
|
+
|
|
93
|
+
// Verificar que el token se estableció
|
|
94
|
+
expect(sdk.auth.isAuthenticated()).toBe(true);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it('debe emitir el evento tokenChanged cuando se actualiza el token', () => {
|
|
98
|
+
const eventHandler = vi.fn();
|
|
99
|
+
sdk.on('tokenChanged', eventHandler);
|
|
100
|
+
|
|
101
|
+
// Establecer token
|
|
102
|
+
sdk.auth.setToken(AUTH_TEST_DATA.loginToken);
|
|
103
|
+
expect(eventHandler).toHaveBeenCalledWith(AUTH_TEST_DATA.loginToken);
|
|
104
|
+
|
|
105
|
+
// Limpiar token
|
|
106
|
+
sdk.auth.setToken(null);
|
|
107
|
+
expect(eventHandler).toHaveBeenCalledWith(null);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('debe limpiar el token cuando se pasa null', () => {
|
|
111
|
+
// Primero establecer un token
|
|
112
|
+
console.log(AUTH_TEST_DATA.loginToken);
|
|
113
|
+
sdk.auth.setToken(AUTH_TEST_DATA.loginToken);
|
|
114
|
+
expect(sdk.auth.isAuthenticated()).toBe(true);
|
|
115
|
+
|
|
116
|
+
// Luego limpiarlo
|
|
117
|
+
sdk.auth.setToken(null);
|
|
118
|
+
|
|
119
|
+
// Verificar que el token se eliminó
|
|
120
|
+
expect(sdk.auth.isAuthenticated()).toBe(false);
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
describe('isAuthenticated', () => {
|
|
125
|
+
it('debe devolver true cuando hay un token', () => {
|
|
126
|
+
sdk.auth.setToken(AUTH_TEST_DATA.loginToken);
|
|
127
|
+
expect(sdk.auth.isAuthenticated()).toBe(true);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('debe devolver false cuando no hay token', () => {
|
|
131
|
+
expect(sdk.auth.isAuthenticated()).toBe(false);
|
|
132
|
+
});
|
|
133
|
+
});
|
|
134
|
+
});
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
2
|
+
import { ClmSdk } from '../../../../src/index';
|
|
3
|
+
import { setupFetchMock, AUTH_TEST_DATA, USERS_TEST_DATA } from '../../../utils/test-utils';
|
|
4
|
+
|
|
5
|
+
describe('UsersApi - getAll', () => {
|
|
6
|
+
let sdk: ClmSdk;
|
|
7
|
+
const TOKEN = AUTH_TEST_DATA.loginToken;
|
|
8
|
+
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
// Inicializar SDK con un token de autenticación
|
|
11
|
+
sdk = new ClmSdk({
|
|
12
|
+
baseUrl: 'https://dev-api.zeroclm.io',
|
|
13
|
+
organization: 'default-org',
|
|
14
|
+
token: TOKEN
|
|
15
|
+
});
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('debe obtener todos los usuarios con paginación predeterminada', async () => {
|
|
19
|
+
// Configurar mock para la petición de usuarios
|
|
20
|
+
setupFetchMock([
|
|
21
|
+
{
|
|
22
|
+
url: '/users',
|
|
23
|
+
method: 'GET',
|
|
24
|
+
response: {
|
|
25
|
+
status: 200,
|
|
26
|
+
data: USERS_TEST_DATA.usersList
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
]);
|
|
30
|
+
|
|
31
|
+
// Obtener usuarios
|
|
32
|
+
const result = await sdk.users.getAll();
|
|
33
|
+
|
|
34
|
+
// Verificar que se hizo la petición correcta
|
|
35
|
+
expect(global.fetch).toHaveBeenCalledTimes(1);
|
|
36
|
+
expect(global.fetch).toHaveBeenCalledWith(
|
|
37
|
+
'https://dev-api.zeroclm.io/users',
|
|
38
|
+
{
|
|
39
|
+
method: 'GET',
|
|
40
|
+
headers: expect.objectContaining({
|
|
41
|
+
'Authorization': `Bearer ${TOKEN}`,
|
|
42
|
+
'Content-Type': 'application/json',
|
|
43
|
+
'X-Organization': 'default-org'
|
|
44
|
+
}),
|
|
45
|
+
credentials: 'include'
|
|
46
|
+
}
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
// Verificar la respuesta
|
|
50
|
+
expect(result).toEqual(USERS_TEST_DATA.usersList);
|
|
51
|
+
expect(result.data.length).toBe(1);
|
|
52
|
+
expect(result.data[0].email).toBe('test@example.com');
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('debe aplicar parámetros de consulta correctamente', async () => {
|
|
56
|
+
// Configurar mock para la petición con parámetros
|
|
57
|
+
setupFetchMock([
|
|
58
|
+
{
|
|
59
|
+
url: '/users',
|
|
60
|
+
method: 'GET',
|
|
61
|
+
response: {
|
|
62
|
+
status: 200,
|
|
63
|
+
data: {
|
|
64
|
+
data: [],
|
|
65
|
+
meta: { total: 0, page: 1, limit: 10, pages: 0 }
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
]);
|
|
70
|
+
|
|
71
|
+
// Parámetros de consulta a enviar
|
|
72
|
+
const queryParams = {
|
|
73
|
+
page: 1,
|
|
74
|
+
limit: 10,
|
|
75
|
+
email: 'ivan@zeroclm.com',
|
|
76
|
+
role_id: 1
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
// Obtener usuarios con parámetros
|
|
80
|
+
await sdk.users.getAll(queryParams);
|
|
81
|
+
|
|
82
|
+
// Verificar que la URL incluye los parámetros correctos
|
|
83
|
+
const calledUrl = (global.fetch as any).mock.calls[0][0];
|
|
84
|
+
expect(calledUrl).toContain('page=1');
|
|
85
|
+
expect(calledUrl).toContain('limit=10');
|
|
86
|
+
expect(calledUrl).toContain('email=ivan%40zeroclm.com');
|
|
87
|
+
expect(calledUrl).toContain('role_id=1');
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('debe manejar respuestas vacías', async () => {
|
|
91
|
+
// Configurar mock para respuesta vacía
|
|
92
|
+
setupFetchMock([
|
|
93
|
+
{
|
|
94
|
+
url: '/users',
|
|
95
|
+
method: 'GET',
|
|
96
|
+
response: {
|
|
97
|
+
status: 200,
|
|
98
|
+
data: {
|
|
99
|
+
data: [],
|
|
100
|
+
meta: { total: 0, page: 1, limit: 20, pages: 0 }
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
]);
|
|
105
|
+
|
|
106
|
+
// Obtener usuarios
|
|
107
|
+
const result = await sdk.users.getAll();
|
|
108
|
+
|
|
109
|
+
// Verificar respuesta vacía
|
|
110
|
+
expect(result.data).toEqual([]);
|
|
111
|
+
expect(result.meta.total).toBe(0);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('debe manejar errores del servidor', async () => {
|
|
115
|
+
// Configurar mock para respuesta de error
|
|
116
|
+
setupFetchMock([
|
|
117
|
+
{
|
|
118
|
+
url: '/users',
|
|
119
|
+
method: 'GET',
|
|
120
|
+
response: {
|
|
121
|
+
status: 500,
|
|
122
|
+
data: {
|
|
123
|
+
statusCode: 500,
|
|
124
|
+
message: 'Internal server error',
|
|
125
|
+
error: 'Server Error'
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
]);
|
|
130
|
+
|
|
131
|
+
// Intentar obtener usuarios y esperar que falle
|
|
132
|
+
await expect(sdk.users.getAll()).rejects.toThrow('Internal server error');
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it('debe manejar errores de autorización', async () => {
|
|
136
|
+
// Configurar mock para respuesta de error de autorización
|
|
137
|
+
setupFetchMock([
|
|
138
|
+
{
|
|
139
|
+
url: '/users',
|
|
140
|
+
method: 'GET',
|
|
141
|
+
response: {
|
|
142
|
+
status: 401,
|
|
143
|
+
data: {
|
|
144
|
+
statusCode: 401,
|
|
145
|
+
message: 'Unauthorized',
|
|
146
|
+
error: 'Unauthorized'
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
]);
|
|
151
|
+
|
|
152
|
+
// Intentar obtener usuarios con token inválido y esperar que falle
|
|
153
|
+
await expect(sdk.users.getAll()).rejects.toThrow('Unauthorized');
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it('debe manejar errores de permisos', async () => {
|
|
157
|
+
// Configurar mock para respuesta de error de permisos
|
|
158
|
+
setupFetchMock([
|
|
159
|
+
{
|
|
160
|
+
url: '/users',
|
|
161
|
+
method: 'GET',
|
|
162
|
+
response: {
|
|
163
|
+
status: 403,
|
|
164
|
+
data: {
|
|
165
|
+
statusCode: 403,
|
|
166
|
+
message: 'Insufficient scope',
|
|
167
|
+
error: 'Forbidden'
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
]);
|
|
172
|
+
|
|
173
|
+
// Intentar obtener usuarios sin permisos suficientes y esperar que falle
|
|
174
|
+
await expect(sdk.users.getAll()).rejects.toThrow('Insufficient scope');
|
|
175
|
+
});
|
|
176
|
+
});
|
package/tests/setup.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { beforeAll, afterEach, vi } from 'vitest';
|
|
2
|
+
|
|
3
|
+
// Setup global fetch mock
|
|
4
|
+
beforeAll(() => {
|
|
5
|
+
global.fetch = vi.fn();
|
|
6
|
+
global.btoa = vi.fn((str) => Buffer.from(str).toString('base64'));
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
// Reset all mocks after each test
|
|
10
|
+
afterEach(() => {
|
|
11
|
+
vi.resetAllMocks();
|
|
12
|
+
});
|