@laboratoria/sdk-js 0.1.1 → 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/README.md +40 -3
- package/index.js +12 -20
- package/lib/core.js +66 -11
- package/lib/curriculum.js +59 -0
- package/lib/model.js +107 -41
- package/package.json +21 -11
- package/schemas/core.json +211 -11
- package/index.spec.js +0 -112
- package/lib/client.spec.js +0 -77
- package/lib/currencies.js +0 -3
- package/lib/model.spec.js +0 -215
- package/lib/team.js +0 -52
- package/schemas/team.json +0 -146
package/schemas/core.json
CHANGED
@@ -1,6 +1,23 @@
|
|
1
1
|
{
|
2
2
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
3
3
|
"definitions": {
|
4
|
+
"Country": {
|
5
|
+
"type": "object",
|
6
|
+
"properties": {
|
7
|
+
"code": {
|
8
|
+
"type": "string"
|
9
|
+
},
|
10
|
+
"name": {
|
11
|
+
"type": "string"
|
12
|
+
},
|
13
|
+
"contracts": {
|
14
|
+
"type": "array",
|
15
|
+
"items": {
|
16
|
+
"$ref": "#/definitions/Contract"
|
17
|
+
}
|
18
|
+
}
|
19
|
+
}
|
20
|
+
},
|
4
21
|
"User": {
|
5
22
|
"type": "object",
|
6
23
|
"properties": {
|
@@ -75,7 +92,8 @@
|
|
75
92
|
]
|
76
93
|
},
|
77
94
|
"disabled": {
|
78
|
-
"type": "boolean"
|
95
|
+
"type": "boolean",
|
96
|
+
"default": false
|
79
97
|
},
|
80
98
|
"students": {
|
81
99
|
"type": "array",
|
@@ -98,6 +116,18 @@
|
|
98
116
|
"type": "null"
|
99
117
|
}
|
100
118
|
]
|
119
|
+
},
|
120
|
+
"contracts": {
|
121
|
+
"type": "array",
|
122
|
+
"items": {
|
123
|
+
"$ref": "#/definitions/Contract"
|
124
|
+
}
|
125
|
+
},
|
126
|
+
"gigs": {
|
127
|
+
"type": "array",
|
128
|
+
"items": {
|
129
|
+
"$ref": "#/definitions/Gig"
|
130
|
+
}
|
101
131
|
}
|
102
132
|
}
|
103
133
|
},
|
@@ -228,6 +258,29 @@
|
|
228
258
|
"type": "string",
|
229
259
|
"format": "date-time"
|
230
260
|
},
|
261
|
+
"vacancies": {
|
262
|
+
"type": [
|
263
|
+
"integer",
|
264
|
+
"null"
|
265
|
+
]
|
266
|
+
},
|
267
|
+
"publicAdmission": {
|
268
|
+
"type": "boolean",
|
269
|
+
"default": false
|
270
|
+
},
|
271
|
+
"placementStart": {
|
272
|
+
"type": [
|
273
|
+
"string",
|
274
|
+
"null"
|
275
|
+
],
|
276
|
+
"format": "date-time"
|
277
|
+
},
|
278
|
+
"placementDuration": {
|
279
|
+
"type": [
|
280
|
+
"integer",
|
281
|
+
"null"
|
282
|
+
]
|
283
|
+
},
|
231
284
|
"program": {
|
232
285
|
"$ref": "#/definitions/Program"
|
233
286
|
},
|
@@ -246,20 +299,26 @@
|
|
246
299
|
"$ref": "#/definitions/Dropout"
|
247
300
|
}
|
248
301
|
},
|
302
|
+
"gigs": {
|
303
|
+
"type": "array",
|
304
|
+
"items": {
|
305
|
+
"$ref": "#/definitions/Gig"
|
306
|
+
}
|
307
|
+
},
|
249
308
|
"links": {
|
250
309
|
"type": "array",
|
251
310
|
"items": {
|
252
311
|
"$ref": "#/definitions/CohortLink"
|
253
312
|
}
|
254
313
|
},
|
255
|
-
"
|
256
|
-
"type": "string"
|
257
|
-
},
|
258
|
-
"signupUser": {
|
314
|
+
"signupUsers": {
|
259
315
|
"type": "array",
|
260
316
|
"items": {
|
261
317
|
"$ref": "#/definitions/User"
|
262
318
|
}
|
319
|
+
},
|
320
|
+
"legacySlug": {
|
321
|
+
"type": "string"
|
263
322
|
}
|
264
323
|
}
|
265
324
|
},
|
@@ -283,7 +342,7 @@
|
|
283
342
|
"null"
|
284
343
|
]
|
285
344
|
},
|
286
|
-
"
|
345
|
+
"legacyStudentCode": {
|
287
346
|
"type": [
|
288
347
|
"string",
|
289
348
|
"null"
|
@@ -346,15 +405,27 @@
|
|
346
405
|
"format": "date-time"
|
347
406
|
},
|
348
407
|
"reason": {
|
349
|
-
"type": "string"
|
408
|
+
"type": "string",
|
409
|
+
"enum": [
|
410
|
+
"dropout",
|
411
|
+
"noShow",
|
412
|
+
"invitedToLeave",
|
413
|
+
"changeCohort"
|
414
|
+
]
|
350
415
|
},
|
351
416
|
"reasonDetail": {
|
352
|
-
"type":
|
417
|
+
"type": [
|
418
|
+
"string",
|
419
|
+
"null"
|
420
|
+
]
|
353
421
|
},
|
354
|
-
"
|
355
|
-
"type":
|
422
|
+
"lastProject": {
|
423
|
+
"type": [
|
424
|
+
"string",
|
425
|
+
"null"
|
426
|
+
]
|
356
427
|
},
|
357
|
-
"
|
428
|
+
"completedProjects": {
|
358
429
|
"type": "integer"
|
359
430
|
},
|
360
431
|
"notes": {
|
@@ -379,10 +450,133 @@
|
|
379
450
|
"$ref": "#/definitions/User"
|
380
451
|
}
|
381
452
|
}
|
453
|
+
},
|
454
|
+
"Contract": {
|
455
|
+
"type": "object",
|
456
|
+
"properties": {
|
457
|
+
"id": {
|
458
|
+
"type": "integer"
|
459
|
+
},
|
460
|
+
"createdAt": {
|
461
|
+
"type": "string",
|
462
|
+
"format": "date-time"
|
463
|
+
},
|
464
|
+
"updatedAt": {
|
465
|
+
"type": "string",
|
466
|
+
"format": "date-time"
|
467
|
+
},
|
468
|
+
"createdBy": {
|
469
|
+
"type": "string"
|
470
|
+
},
|
471
|
+
"start": {
|
472
|
+
"type": "string",
|
473
|
+
"format": "date-time"
|
474
|
+
},
|
475
|
+
"end": {
|
476
|
+
"type": [
|
477
|
+
"string",
|
478
|
+
"null"
|
479
|
+
],
|
480
|
+
"format": "date-time"
|
481
|
+
},
|
482
|
+
"hoursPerWeek": {
|
483
|
+
"type": "integer"
|
484
|
+
},
|
485
|
+
"isEmployment": {
|
486
|
+
"type": "boolean"
|
487
|
+
},
|
488
|
+
"currency": {
|
489
|
+
"type": "string",
|
490
|
+
"enum": [
|
491
|
+
"BRL",
|
492
|
+
"CLP",
|
493
|
+
"COP",
|
494
|
+
"MXN",
|
495
|
+
"PEN",
|
496
|
+
"USD"
|
497
|
+
]
|
498
|
+
},
|
499
|
+
"feeBasis": {
|
500
|
+
"type": "string",
|
501
|
+
"enum": [
|
502
|
+
"HOURLY",
|
503
|
+
"MONTHLY"
|
504
|
+
]
|
505
|
+
},
|
506
|
+
"feeAmount": {
|
507
|
+
"type": "integer"
|
508
|
+
},
|
509
|
+
"user": {
|
510
|
+
"$ref": "#/definitions/User"
|
511
|
+
},
|
512
|
+
"country": {
|
513
|
+
"$ref": "#/definitions/Country"
|
514
|
+
},
|
515
|
+
"gigs": {
|
516
|
+
"type": "array",
|
517
|
+
"items": {
|
518
|
+
"$ref": "#/definitions/Gig"
|
519
|
+
}
|
520
|
+
}
|
521
|
+
}
|
522
|
+
},
|
523
|
+
"Gig": {
|
524
|
+
"type": "object",
|
525
|
+
"properties": {
|
526
|
+
"id": {
|
527
|
+
"type": "integer"
|
528
|
+
},
|
529
|
+
"createdAt": {
|
530
|
+
"type": "string",
|
531
|
+
"format": "date-time"
|
532
|
+
},
|
533
|
+
"updatedAt": {
|
534
|
+
"type": "string",
|
535
|
+
"format": "date-time"
|
536
|
+
},
|
537
|
+
"createdBy": {
|
538
|
+
"type": "string"
|
539
|
+
},
|
540
|
+
"start": {
|
541
|
+
"type": "string",
|
542
|
+
"format": "date-time"
|
543
|
+
},
|
544
|
+
"end": {
|
545
|
+
"type": [
|
546
|
+
"string",
|
547
|
+
"null"
|
548
|
+
],
|
549
|
+
"format": "date-time"
|
550
|
+
},
|
551
|
+
"hoursPerWeek": {
|
552
|
+
"type": "integer"
|
553
|
+
},
|
554
|
+
"role": {
|
555
|
+
"type": "string",
|
556
|
+
"enum": [
|
557
|
+
"bm",
|
558
|
+
"pdc",
|
559
|
+
"js",
|
560
|
+
"ux"
|
561
|
+
]
|
562
|
+
},
|
563
|
+
"user": {
|
564
|
+
"$ref": "#/definitions/User"
|
565
|
+
},
|
566
|
+
"contract": {
|
567
|
+
"$ref": "#/definitions/Contract"
|
568
|
+
},
|
569
|
+
"cohort": {
|
570
|
+
"$ref": "#/definitions/Cohort"
|
571
|
+
}
|
572
|
+
}
|
382
573
|
}
|
383
574
|
},
|
384
575
|
"type": "object",
|
385
576
|
"properties": {
|
577
|
+
"country": {
|
578
|
+
"$ref": "#/definitions/Country"
|
579
|
+
},
|
386
580
|
"user": {
|
387
581
|
"$ref": "#/definitions/User"
|
388
582
|
},
|
@@ -406,6 +600,12 @@
|
|
406
600
|
},
|
407
601
|
"dropout": {
|
408
602
|
"$ref": "#/definitions/Dropout"
|
603
|
+
},
|
604
|
+
"contract": {
|
605
|
+
"$ref": "#/definitions/Contract"
|
606
|
+
},
|
607
|
+
"gig": {
|
608
|
+
"$ref": "#/definitions/Gig"
|
409
609
|
}
|
410
610
|
}
|
411
611
|
}
|
package/index.spec.js
DELETED
@@ -1,112 +0,0 @@
|
|
1
|
-
import { initializeApp } from 'firebase/app';
|
2
|
-
import {
|
3
|
-
getAuth,
|
4
|
-
onAuthStateChanged,
|
5
|
-
signInWithEmailAndPassword,
|
6
|
-
signOut,
|
7
|
-
} from 'firebase/auth';
|
8
|
-
import { createClient } from './lib/client.js';
|
9
|
-
import { createApp } from './index.js';
|
10
|
-
|
11
|
-
jest.mock('./lib/client.js');
|
12
|
-
|
13
|
-
beforeEach(() => {
|
14
|
-
initializeApp.mockClear();
|
15
|
-
onAuthStateChanged.mockClear();
|
16
|
-
signInWithEmailAndPassword.mockClear();
|
17
|
-
});
|
18
|
-
|
19
|
-
describe('createApp', () => {
|
20
|
-
it('should invoke firebase\'s initializaApp', () => {
|
21
|
-
createApp();
|
22
|
-
expect(initializeApp).toHaveBeenCalledTimes(1);
|
23
|
-
expect(initializeApp.mock.calls[0]).toMatchSnapshot();
|
24
|
-
});
|
25
|
-
});
|
26
|
-
|
27
|
-
describe('app.auth.onChange', () => {
|
28
|
-
it('should listen to firebase\'s onAuthStateChanged and notify subscribers when not authenticated', (done) => {
|
29
|
-
const { auth } = createApp();
|
30
|
-
|
31
|
-
onAuthStateChanged.mockImplementationOnce((_, cb) => {
|
32
|
-
cb();
|
33
|
-
return () => { };
|
34
|
-
});
|
35
|
-
|
36
|
-
auth.onChange(({ authUser, user }) => {
|
37
|
-
expect(authUser).toBeNull();
|
38
|
-
expect(user).toBeNull();
|
39
|
-
done();
|
40
|
-
});
|
41
|
-
});
|
42
|
-
|
43
|
-
it('should fetch user from db when authenticated and add isStaff, isManager, etc', (done) => {
|
44
|
-
const { auth } = createApp();
|
45
|
-
const mockAuthUser = { uid: 'xxx', getIdToken: () => 'token' };
|
46
|
-
const userMock = { uid: 'xxx', email: 'foo@bar.baz' };
|
47
|
-
|
48
|
-
onAuthStateChanged.mockImplementationOnce((_, cb) => {
|
49
|
-
cb(mockAuthUser);
|
50
|
-
return () => { };
|
51
|
-
});
|
52
|
-
|
53
|
-
createClient().mockResolvedValueOnce(userMock);
|
54
|
-
|
55
|
-
auth.onChange(({ authUser, user }) => {
|
56
|
-
expect(authUser).toEqual(mockAuthUser);
|
57
|
-
expect(user).toEqual({
|
58
|
-
...userMock,
|
59
|
-
isStaff: false,
|
60
|
-
isManager: false,
|
61
|
-
isFinance: false,
|
62
|
-
isAdmin: false,
|
63
|
-
});
|
64
|
-
done();
|
65
|
-
});
|
66
|
-
});
|
67
|
-
|
68
|
-
it('should log error and reset state (authUser = null, user = null) when fetch user from db fails', (done) => {
|
69
|
-
const { auth } = createApp();
|
70
|
-
const mockAuthUser = { uid: 'xxx', getIdToken: () => 'token' };
|
71
|
-
const spy = jest.spyOn(console, 'error').mockImplementationOnce(() => { })
|
72
|
-
const error = new Error('OMG');
|
73
|
-
|
74
|
-
onAuthStateChanged.mockImplementationOnce((_, cb) => {
|
75
|
-
cb(mockAuthUser);
|
76
|
-
return () => { };
|
77
|
-
});
|
78
|
-
|
79
|
-
createClient().mockRejectedValueOnce(error);
|
80
|
-
|
81
|
-
auth.onChange(({ authUser, user }) => {
|
82
|
-
expect(authUser).toBeNull();
|
83
|
-
expect(user).toBeNull();
|
84
|
-
expect(spy).toHaveBeenCalledWith(error);
|
85
|
-
spy.mockRestore();
|
86
|
-
done();
|
87
|
-
});
|
88
|
-
});
|
89
|
-
});
|
90
|
-
|
91
|
-
describe('app.auth.signIn', () => {
|
92
|
-
it('should delegate to firebase\'s signInWithEmailAndPassword', async () => {
|
93
|
-
const { auth } = createApp();
|
94
|
-
const email = 'foo@bar.baz';
|
95
|
-
const pass = 'secret';
|
96
|
-
|
97
|
-
await auth.signIn(email, pass);
|
98
|
-
|
99
|
-
expect(signInWithEmailAndPassword).toHaveBeenCalledTimes(1);
|
100
|
-
expect(signInWithEmailAndPassword).toHaveBeenCalledWith({}, email, pass);
|
101
|
-
});
|
102
|
-
});
|
103
|
-
|
104
|
-
describe('app.auth.signOut', () => {
|
105
|
-
it('should delegate to firebase\'s signOut', async () => {
|
106
|
-
const { auth } = createApp();
|
107
|
-
|
108
|
-
await auth.signOut();
|
109
|
-
|
110
|
-
expect(signOut).toHaveBeenCalledTimes(1);
|
111
|
-
});
|
112
|
-
});
|
package/lib/client.spec.js
DELETED
@@ -1,77 +0,0 @@
|
|
1
|
-
import { createClient } from './client.js';
|
2
|
-
|
3
|
-
describe('client', () => {
|
4
|
-
|
5
|
-
beforeAll(() => window.fetch = jest.fn());
|
6
|
-
|
7
|
-
afterEach(() => {
|
8
|
-
window.fetch.mockClear();
|
9
|
-
jest.restoreAllMocks();
|
10
|
-
});
|
11
|
-
|
12
|
-
it('should delegate to global fetch and add mode:cors and parse JSON resp when OK', async () => {
|
13
|
-
window.fetch.mockResolvedValue({
|
14
|
-
json: jest.fn().mockResolvedValue({ ok: true }),
|
15
|
-
});
|
16
|
-
const baseUrl = 'http://foo.bar';
|
17
|
-
const client = createClient(baseUrl);
|
18
|
-
expect(await client('/')).toEqual({ ok: true });
|
19
|
-
expect(window.fetch).toHaveBeenCalledTimes(1);
|
20
|
-
expect(window.fetch).toHaveBeenCalledWith(`${baseUrl}/`, {
|
21
|
-
mode: 'cors',
|
22
|
-
headers: {},
|
23
|
-
});
|
24
|
-
});
|
25
|
-
|
26
|
-
it('should reject when response.status > 202', async () => {
|
27
|
-
window.fetch.mockResolvedValue({
|
28
|
-
status: 400,
|
29
|
-
json: jest.fn().mockResolvedValue({ ok: false }),
|
30
|
-
});
|
31
|
-
const baseUrl = 'http://foo.bar';
|
32
|
-
const client = createClient(baseUrl);
|
33
|
-
await expect(client('/')).rejects.toThrow('HTTP Error 400');
|
34
|
-
expect(window.fetch).toHaveBeenCalledTimes(1);
|
35
|
-
expect(window.fetch).toHaveBeenCalledWith(`${baseUrl}/`, {
|
36
|
-
mode: 'cors',
|
37
|
-
headers: {},
|
38
|
-
});
|
39
|
-
});
|
40
|
-
|
41
|
-
it('should add token when authUser present', async () => {
|
42
|
-
window.fetch.mockResolvedValue({
|
43
|
-
json: jest.fn().mockResolvedValue({ ok: true }),
|
44
|
-
});
|
45
|
-
const baseUrl = 'http://foo.bar';
|
46
|
-
const user = { getIdToken: jest.fn().mockReturnValueOnce('xxx') };
|
47
|
-
const client = createClient(baseUrl, user);
|
48
|
-
expect(await client('/')).toEqual({ ok: true });
|
49
|
-
expect(window.fetch).toHaveBeenCalledTimes(1);
|
50
|
-
expect(window.fetch).toHaveBeenCalledWith(`${baseUrl}/`, {
|
51
|
-
mode: 'cors',
|
52
|
-
headers: {
|
53
|
-
authorization: 'Bearer xxx',
|
54
|
-
},
|
55
|
-
});
|
56
|
-
expect(user.getIdToken).toHaveBeenCalledTimes(1);
|
57
|
-
});
|
58
|
-
|
59
|
-
it('should add content-type header and stringify body when necessary', async () => {
|
60
|
-
window.fetch.mockResolvedValue({
|
61
|
-
json: jest.fn().mockResolvedValue({ ok: true }),
|
62
|
-
});
|
63
|
-
const baseUrl = 'http://foo.bar';
|
64
|
-
const client = createClient(baseUrl);
|
65
|
-
const body = { foo: 'bar' };
|
66
|
-
expect(await client('/', { method: 'POST', body })).toEqual({ ok: true });
|
67
|
-
expect(window.fetch).toHaveBeenCalledTimes(1);
|
68
|
-
expect(window.fetch).toHaveBeenCalledWith(`${baseUrl}/`, {
|
69
|
-
mode: 'cors',
|
70
|
-
headers: {
|
71
|
-
'content-type': 'application/json',
|
72
|
-
},
|
73
|
-
method: 'POST',
|
74
|
-
body: JSON.stringify(body),
|
75
|
-
});
|
76
|
-
});
|
77
|
-
});
|
package/lib/currencies.js
DELETED
package/lib/model.spec.js
DELETED
@@ -1,215 +0,0 @@
|
|
1
|
-
import createModel from './model.js';
|
2
|
-
import { createClient } from './client.js';
|
3
|
-
|
4
|
-
jest.mock('./client.js');
|
5
|
-
|
6
|
-
beforeEach(() => createClient().mockClear());
|
7
|
-
|
8
|
-
describe('model.schema', () => {
|
9
|
-
it('should be empty object by default', () => {
|
10
|
-
const model = createModel('http://1.2.3.4', {}, 'foo');
|
11
|
-
expect(model.schema).toEqual({});
|
12
|
-
});
|
13
|
-
|
14
|
-
it('should get the model\'s schema', () => {
|
15
|
-
const schema = {
|
16
|
-
properties: {
|
17
|
-
a: { type: 'string' },
|
18
|
-
},
|
19
|
-
};
|
20
|
-
const model = createModel('http://1.2.3.4', {}, 'foo', schema);
|
21
|
-
expect(model.schema).toEqual(schema);
|
22
|
-
});
|
23
|
-
});
|
24
|
-
|
25
|
-
describe('model.findMany(options)', () => {
|
26
|
-
it('should send GET request', async () => {
|
27
|
-
const schema = {
|
28
|
-
properties: {
|
29
|
-
id: { type: 'integer' },
|
30
|
-
createdAt: { type: 'string', format: 'date-time' },
|
31
|
-
},
|
32
|
-
};
|
33
|
-
const now = new Date();
|
34
|
-
const client = createClient().mockResolvedValue([{
|
35
|
-
id: 1,
|
36
|
-
createdAt: now.toISOString(),
|
37
|
-
}]);
|
38
|
-
const model = createModel('http://1.2.3.4', {}, 'foo', schema);
|
39
|
-
const results = await model.findMany();
|
40
|
-
expect(results).toEqual([{ id: 1, createdAt: now }]);
|
41
|
-
expect(results[0].createdAt instanceof Date).toBe(true);
|
42
|
-
expect(client).toHaveBeenCalledTimes(1);
|
43
|
-
expect(client).toHaveBeenCalledWith('/foo');
|
44
|
-
});
|
45
|
-
});
|
46
|
-
|
47
|
-
describe('model.findById(id, options)', () => {
|
48
|
-
it('should send GET request', async () => {
|
49
|
-
const client = createClient().mockResolvedValue({});
|
50
|
-
const model = createModel('http://1.2.3.4', {}, 'foo');
|
51
|
-
expect(await model.findById(1)).toEqual({});
|
52
|
-
expect(client).toHaveBeenCalledTimes(1);
|
53
|
-
expect(client).toHaveBeenCalledWith('/foo/1');
|
54
|
-
});
|
55
|
-
});
|
56
|
-
|
57
|
-
describe('model.create(options)', () => {
|
58
|
-
it('should send POST request', async () => {
|
59
|
-
const client = createClient().mockResolvedValue({});
|
60
|
-
const model = createModel('http://1.2.3.4', {}, 'foo');
|
61
|
-
expect(await model.create({ data: { ok: true } })).toEqual({});
|
62
|
-
expect(client).toHaveBeenCalledTimes(1);
|
63
|
-
expect(client).toHaveBeenCalledWith('/foo', {
|
64
|
-
body: { data: { ok: true } },
|
65
|
-
method: 'POST',
|
66
|
-
});
|
67
|
-
});
|
68
|
-
});
|
69
|
-
|
70
|
-
describe('model.update(options)', () => {
|
71
|
-
it('should send POST request', async () => {
|
72
|
-
const client = createClient().mockResolvedValue({});
|
73
|
-
const model = createModel('http://1.2.3.4', {}, 'foo');
|
74
|
-
expect(await model.update({ where: { id: 1 }, data: { ok: true } })).toEqual({});
|
75
|
-
expect(client).toHaveBeenCalledTimes(1);
|
76
|
-
expect(client).toHaveBeenCalledWith('/foo/1', {
|
77
|
-
body: { where: { id: 1 }, data: { ok: true } },
|
78
|
-
method: 'PUT',
|
79
|
-
});
|
80
|
-
});
|
81
|
-
});
|
82
|
-
|
83
|
-
describe('model.upsert(options)', () => {
|
84
|
-
it('should send POST request when new row', async () => {
|
85
|
-
const client = createClient().mockResolvedValue({});
|
86
|
-
const model = createModel('http://1.2.3.4', {}, 'foo');
|
87
|
-
const result = await model.upsert({
|
88
|
-
where: {},
|
89
|
-
create: { ok: true },
|
90
|
-
});
|
91
|
-
expect(result).toEqual({});
|
92
|
-
expect(client).toHaveBeenCalledTimes(1);
|
93
|
-
expect(client).toHaveBeenCalledWith('/foo', {
|
94
|
-
body: { data: { ok: true } },
|
95
|
-
method: 'POST',
|
96
|
-
});
|
97
|
-
});
|
98
|
-
|
99
|
-
it('should send PUT request when existing row', async () => {
|
100
|
-
const client = createClient().mockResolvedValue({});
|
101
|
-
const model = createModel('http://1.2.3.4', {}, 'foo');
|
102
|
-
const result = await model.upsert({
|
103
|
-
where: { id: 1 },
|
104
|
-
update: { ok: true },
|
105
|
-
});
|
106
|
-
expect(result).toEqual({});
|
107
|
-
expect(client).toHaveBeenCalledTimes(1);
|
108
|
-
expect(client).toHaveBeenCalledWith('/foo/1', {
|
109
|
-
body: {
|
110
|
-
where: { id: 1 },
|
111
|
-
data: { ok: true },
|
112
|
-
},
|
113
|
-
method: 'PUT',
|
114
|
-
});
|
115
|
-
});
|
116
|
-
});
|
117
|
-
|
118
|
-
describe('model.delete(id)', () => {
|
119
|
-
it('should send POST request', async () => {
|
120
|
-
const client = createClient().mockResolvedValue({});
|
121
|
-
const model = createModel('http://1.2.3.4', {}, 'foo');
|
122
|
-
expect(await model.delete(1)).toEqual({});
|
123
|
-
expect(client).toHaveBeenCalledTimes(1);
|
124
|
-
expect(client).toHaveBeenCalledWith('/foo/1', {
|
125
|
-
method: 'DELETE',
|
126
|
-
});
|
127
|
-
});
|
128
|
-
});
|
129
|
-
|
130
|
-
describe('model.validateAttr(key, value)', () => {
|
131
|
-
it('should not validate when no schema', () => {
|
132
|
-
const model = createModel('http://1.2.3.4', {}, 'foo');
|
133
|
-
expect(model.validateAttr('a', 1)).toBeUndefined();
|
134
|
-
});
|
135
|
-
|
136
|
-
it('should validate text when required', () => {
|
137
|
-
const schema = {
|
138
|
-
properties: {
|
139
|
-
a: { type: 'string' },
|
140
|
-
},
|
141
|
-
};
|
142
|
-
const model = createModel('http://1.2.3.4', {}, 'foo', schema);
|
143
|
-
expect(model.validateAttr('a', '')).toBe('Field is required');
|
144
|
-
});
|
145
|
-
|
146
|
-
it('should validate number when required', () => {
|
147
|
-
const schema = {
|
148
|
-
properties: {
|
149
|
-
a: { type: 'integer', required: true },
|
150
|
-
},
|
151
|
-
};
|
152
|
-
const model = createModel('http://1.2.3.4', {}, 'foo', schema);
|
153
|
-
expect(model.validateAttr('a', 'foo')).toBe('Invalid number format');
|
154
|
-
});
|
155
|
-
|
156
|
-
it('should validate enum', () => {
|
157
|
-
const schema = {
|
158
|
-
properties: {
|
159
|
-
a: { type: 'integer', enum: [1, 2, 3] },
|
160
|
-
},
|
161
|
-
};
|
162
|
-
const model = createModel('http://1.2.3.4', {}, 'foo', schema);
|
163
|
-
expect(model.validateAttr('a', 'foo')).toBe('foo is not one of: 1,2,3');
|
164
|
-
});
|
165
|
-
|
166
|
-
it('should allow empty enum when not required', () => {
|
167
|
-
const schema = {
|
168
|
-
properties: {
|
169
|
-
a: { type: ['integer', 'null'], enum: [1, 2, 3] },
|
170
|
-
},
|
171
|
-
};
|
172
|
-
const model = createModel('http://1.2.3.4', {}, 'foo', schema);
|
173
|
-
expect(model.validateAttr('a', null)).toBeUndefined();
|
174
|
-
expect(model.validateAttr('a', undefined)).toBeUndefined();
|
175
|
-
expect(model.validateAttr('a', '')).toBeUndefined();
|
176
|
-
});
|
177
|
-
});
|
178
|
-
|
179
|
-
describe('model.validate(attributes)', () => {
|
180
|
-
it('should not validate when no schema', () => {
|
181
|
-
const model = createModel('http://1.2.3.4', {}, 'foo');
|
182
|
-
expect(model.validate({ a: 1 })).toEqual({});
|
183
|
-
});
|
184
|
-
|
185
|
-
it('should validate when schema present', () => {
|
186
|
-
const schema = {
|
187
|
-
properties: {
|
188
|
-
a: { type: 'string' },
|
189
|
-
b: { type: 'integer' },
|
190
|
-
},
|
191
|
-
};
|
192
|
-
const model = createModel('http://1.2.3.4', {}, 'foo', schema);
|
193
|
-
expect(model.validate({ a: '', b: 1 })).toEqual({ a: 'Field is required' });
|
194
|
-
});
|
195
|
-
|
196
|
-
it('should validate number when required', () => {
|
197
|
-
const schema = {
|
198
|
-
properties: {
|
199
|
-
a: { type: 'integer' },
|
200
|
-
},
|
201
|
-
};
|
202
|
-
const model = createModel('http://1.2.3.4', {}, 'foo', schema);
|
203
|
-
expect(model.validateAttr('a', 'foo')).toBe('Invalid number format');
|
204
|
-
});
|
205
|
-
|
206
|
-
it('should validate enum', () => {
|
207
|
-
const schema = {
|
208
|
-
properties: {
|
209
|
-
a: { type: 'integer', enum: [1, 2, 3] },
|
210
|
-
},
|
211
|
-
};
|
212
|
-
const model = createModel('http://1.2.3.4', {}, 'foo', schema);
|
213
|
-
expect(model.validateAttr('a', 'foo')).toBe('foo is not one of: 1,2,3');
|
214
|
-
});
|
215
|
-
});
|