@laboratoria/sdk-js 1.0.0 → 1.4.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/lib/core.js +13 -24
- package/lib/model.js +119 -33
- package/package.json +10 -10
- package/schemas/core.json +33 -17
- package/.github/workflows/node.js.yml +0 -31
- package/index.spec.js +0 -112
- package/lib/client.spec.js +0 -77
- package/lib/currencies.js +0 -3
- package/lib/curriculum.spec.js +0 -194
- package/lib/model.spec.js +0 -242
package/lib/core.js
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
import md5 from 'blueimp-md5';
|
2
|
-
import currencies from './currencies';
|
3
|
-
import roles from './roles';
|
4
2
|
import { createModels, extendSchemaDefinitions } from './model';
|
5
3
|
import schema from '../schemas/core.json';
|
6
4
|
|
7
5
|
const extended = {
|
8
6
|
Country: {
|
7
|
+
primaryKey: 'code',
|
9
8
|
plural: 'countries',
|
9
|
+
searchProps: ['code', 'name'],
|
10
10
|
},
|
11
11
|
User: {
|
12
12
|
primaryKey: 'uid',
|
@@ -122,39 +122,33 @@ const extended = {
|
|
122
122
|
Contract: {
|
123
123
|
inputProps: [
|
124
124
|
'user',
|
125
|
-
'
|
126
|
-
'currency',
|
125
|
+
'country',
|
127
126
|
'isEmployment',
|
128
|
-
'feeBasis',
|
129
127
|
'feeAmount',
|
130
128
|
'hoursPerWeek',
|
131
129
|
'start',
|
132
130
|
'end',
|
131
|
+
'isTrial',
|
132
|
+
'checkPilot',
|
133
|
+
'source',
|
133
134
|
],
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
},
|
141
|
-
},
|
135
|
+
searchProps: [
|
136
|
+
'user.firstName',
|
137
|
+
'user.lastName',
|
138
|
+
'user.email',
|
139
|
+
],
|
140
|
+
getOptionLabel: ({ id, user }) => `${user?.firstName} (id: ${id})`,
|
142
141
|
},
|
143
142
|
Gig: {
|
144
143
|
inputProps: [
|
145
|
-
// 'contract',
|
146
144
|
'cohort',
|
147
145
|
'user',
|
146
|
+
'contract',
|
148
147
|
'role',
|
149
148
|
'hoursPerWeek',
|
150
149
|
'start',
|
151
150
|
'end',
|
152
151
|
],
|
153
|
-
properties: {
|
154
|
-
role: {
|
155
|
-
enum: roles,
|
156
|
-
},
|
157
|
-
},
|
158
152
|
},
|
159
153
|
};
|
160
154
|
|
@@ -162,8 +156,3 @@ export const createAPI = (url, state) => createModels(url, state, {
|
|
162
156
|
...schema,
|
163
157
|
definitions: extendSchemaDefinitions(schema, extended),
|
164
158
|
});
|
165
|
-
|
166
|
-
// const {
|
167
|
-
// delete: _,
|
168
|
-
// ...userAPI,
|
169
|
-
// } = createModel(coreApiUrl, state, 'users', schemas.user);
|
package/lib/model.js
CHANGED
@@ -1,6 +1,38 @@
|
|
1
1
|
import { createClient } from './client.js';
|
2
2
|
|
3
3
|
|
4
|
+
const isRequiredOneToOneRelation = (schema, key) => (
|
5
|
+
!!schema.properties
|
6
|
+
&& !!schema.properties[key]
|
7
|
+
&& !!schema.properties[key].$ref
|
8
|
+
);
|
9
|
+
|
10
|
+
const isOptionalOneToOneRelation = (schema, key) => (
|
11
|
+
!!schema.properties
|
12
|
+
&& !!schema.properties[key]
|
13
|
+
&& Array.isArray(schema.properties[key].anyOf)
|
14
|
+
&& !!schema.properties[key].anyOf[0]?.$ref
|
15
|
+
&& schema.properties[key].anyOf[1]?.type === 'null'
|
16
|
+
);
|
17
|
+
|
18
|
+
// const isOneToOneRelation = (schema, key) => (
|
19
|
+
// isRequiredOneToOneRelation(schema, key)
|
20
|
+
// || isOptionalOneToOneRelation(schema, key)
|
21
|
+
// );
|
22
|
+
|
23
|
+
const isOneToManyRelation = (schema, key) => (
|
24
|
+
schema.properties
|
25
|
+
&& schema.properties[key]
|
26
|
+
&& schema.properties[key].type === 'array'
|
27
|
+
&& !!schema.properties[key].items.$ref
|
28
|
+
);
|
29
|
+
|
30
|
+
// const isRelation = (schema, key) => (
|
31
|
+
// isOneToOneRelation(schema, key)
|
32
|
+
// || isOneToManyRelation(schema, key)
|
33
|
+
// );
|
34
|
+
|
35
|
+
|
4
36
|
const createValidator = (schema) => {
|
5
37
|
const properties = schema.properties || {};
|
6
38
|
const inputProps = schema.inputProps || Object.keys(properties);
|
@@ -73,20 +105,12 @@ const createBuildURL = collectionName => (id, q) => {
|
|
73
105
|
|
74
106
|
const serializeData = (data, schema) => {
|
75
107
|
const hasInputProps = Array.isArray(schema.inputProps);
|
76
|
-
|
108
|
+
return Object.keys(data).reduce(
|
77
109
|
(memo, key) => {
|
78
110
|
if (hasInputProps && !schema.inputProps.includes(key)) {
|
79
111
|
return memo;
|
80
112
|
}
|
81
|
-
|
82
|
-
const isOptionalRelation = (
|
83
|
-
prop
|
84
|
-
&& Array.isArray(prop.anyOf)
|
85
|
-
&& prop.anyOf[0].$ref
|
86
|
-
&& prop.anyOf[1]
|
87
|
-
&& prop.anyOf[1].type === 'null'
|
88
|
-
);
|
89
|
-
if (isOptionalRelation && data[key] === null) {
|
113
|
+
if (isOptionalOneToOneRelation(schema, key) && data[key] === null) {
|
90
114
|
return memo;
|
91
115
|
}
|
92
116
|
return {
|
@@ -96,36 +120,61 @@ const serializeData = (data, schema) => {
|
|
96
120
|
},
|
97
121
|
{},
|
98
122
|
);
|
99
|
-
|
100
|
-
// {
|
101
|
-
// signupCohort: {
|
102
|
-
// connect: { id: signupCohort.id },
|
103
|
-
// },
|
104
|
-
// }
|
105
|
-
|
106
|
-
return payload;
|
107
123
|
};
|
108
124
|
|
109
125
|
|
110
|
-
export const createModel = (baseUrl, state, collectionName, schema = {}) => {
|
126
|
+
export const createModel = (baseUrl, state, collectionName, schema = {}, models = {}) => {
|
111
127
|
const primaryKey = schema.primaryKey || 'id';
|
112
128
|
const validator = createValidator(schema);
|
113
129
|
const buildURL = createBuildURL(collectionName);
|
114
130
|
const req = (...args) => createClient(baseUrl, state.authUser)(...args);
|
115
|
-
const create = q => req(buildURL(), {
|
131
|
+
const create = ({ data, ...q }) => req(buildURL(null, q), {
|
116
132
|
method: 'POST',
|
117
|
-
body:
|
118
|
-
});
|
119
|
-
|
120
|
-
const put = q => req(buildURL(q.where[primaryKey]), {
|
121
|
-
method: 'PUT',
|
122
|
-
body: Object.assign(q, { data: serializeData(q.data, schema) }),
|
133
|
+
body: serializeData(data, schema),
|
123
134
|
});
|
135
|
+
const put = ({ data, ...q }) => {
|
136
|
+
const { where, ...rest } = q;
|
137
|
+
return req(buildURL(where[primaryKey], rest), {
|
138
|
+
method: 'PUT',
|
139
|
+
body: serializeData(data, schema),
|
140
|
+
});
|
141
|
+
};
|
124
142
|
|
125
143
|
const parse = data => {
|
144
|
+
if (!data) {
|
145
|
+
return data;
|
146
|
+
}
|
147
|
+
|
126
148
|
const parsed = Object.keys(data).reduce(
|
127
149
|
(memo, key) => {
|
128
|
-
const
|
150
|
+
const propSchema = schema.properties[key] || {};
|
151
|
+
const { type, format, items } = propSchema;
|
152
|
+
if (items && isOneToManyRelation(schema, key)) {
|
153
|
+
const relationModelName = items.$ref.split('/').pop().toLowerCase();
|
154
|
+
return {
|
155
|
+
...memo,
|
156
|
+
[key]: (
|
157
|
+
typeof models[relationModelName]?.parse === 'function'
|
158
|
+
? data[key].map(obj => models[relationModelName].parse(obj))
|
159
|
+
: data[key]
|
160
|
+
),
|
161
|
+
};
|
162
|
+
}
|
163
|
+
const ref = (
|
164
|
+
isRequiredOneToOneRelation(schema, key)
|
165
|
+
? propSchema.$ref
|
166
|
+
: isOptionalOneToOneRelation(schema, key)
|
167
|
+
? propSchema.anyOf[0]?.$ref
|
168
|
+
: null
|
169
|
+
);
|
170
|
+
|
171
|
+
if (ref) {
|
172
|
+
const relationModelName = ref.split('/').pop().toLowerCase();
|
173
|
+
return {
|
174
|
+
...memo,
|
175
|
+
[key]: models[relationModelName].parse(data[key]),
|
176
|
+
};
|
177
|
+
}
|
129
178
|
return {
|
130
179
|
...memo,
|
131
180
|
[key]: (
|
@@ -144,16 +193,50 @@ export const createModel = (baseUrl, state, collectionName, schema = {}) => {
|
|
144
193
|
);
|
145
194
|
};
|
146
195
|
|
196
|
+
const relations = Object.keys(schema.properties || {}).reduce(
|
197
|
+
(memo, key) => (
|
198
|
+
isRequiredOneToOneRelation(schema, key)
|
199
|
+
? Object.assign(memo, {
|
200
|
+
all: memo.all.concat(key),
|
201
|
+
oneToOne: memo.oneToOne.concat(key),
|
202
|
+
requiredOneToOne: memo.requiredOneToOne.concat(key),
|
203
|
+
})
|
204
|
+
: isOptionalOneToOneRelation(schema, key)
|
205
|
+
? Object.assign(memo, {
|
206
|
+
all: memo.all.concat(key),
|
207
|
+
oneToOne: memo.oneToOne.concat(key),
|
208
|
+
optionalOneToOne: memo.optionalOneToOne.concat(key),
|
209
|
+
})
|
210
|
+
: isOneToManyRelation(schema, key)
|
211
|
+
? Object.assign(memo, {
|
212
|
+
all: memo.all.concat(key),
|
213
|
+
oneToMany: memo.oneToMany.concat(key),
|
214
|
+
})
|
215
|
+
: memo
|
216
|
+
),
|
217
|
+
{
|
218
|
+
all: [],
|
219
|
+
oneToOne: [],
|
220
|
+
requiredOneToOne: [],
|
221
|
+
optionalOneToOne: [],
|
222
|
+
oneToMany: [],
|
223
|
+
},
|
224
|
+
);
|
225
|
+
|
147
226
|
return {
|
148
227
|
get schema() {
|
149
|
-
return schema;
|
228
|
+
return { ...schema, primaryKey };
|
150
229
|
},
|
230
|
+
get relations() {
|
231
|
+
return relations;
|
232
|
+
},
|
233
|
+
parse,
|
151
234
|
validateAttr: validator.validateAttr,
|
152
235
|
validate: validator.validate,
|
153
236
|
findMany: q => req(buildURL(null, q))
|
154
237
|
.then(results => results.map(parse)),
|
155
238
|
findById: (id, q) => req(buildURL(id, q))
|
156
|
-
.then(
|
239
|
+
.then(parse),
|
157
240
|
create,
|
158
241
|
update: put,
|
159
242
|
upsert: opts => (
|
@@ -162,27 +245,30 @@ export const createModel = (baseUrl, state, collectionName, schema = {}) => {
|
|
162
245
|
: put({ where: opts.where, data: opts.update })
|
163
246
|
),
|
164
247
|
delete: id => req(buildURL(id), { method: 'DELETE' }),
|
248
|
+
stats: () => req(buildURL('_stats')),
|
165
249
|
};
|
166
250
|
};
|
167
251
|
|
252
|
+
|
168
253
|
export const createModels = (url, state, schema) => {
|
169
254
|
return Object.keys(schema.properties).reduce(
|
170
255
|
(prev, key) => {
|
171
256
|
const name = schema.properties[key].$ref.split('/').pop();
|
172
|
-
return {
|
173
|
-
...prev,
|
257
|
+
return Object.assign(prev, {
|
174
258
|
[key]: createModel(
|
175
259
|
url,
|
176
260
|
state,
|
177
261
|
schema.definitions[name].plural || `${key}s`,
|
178
262
|
schema.definitions[name],
|
263
|
+
prev,
|
179
264
|
),
|
180
|
-
};
|
265
|
+
});
|
181
266
|
},
|
182
267
|
{},
|
183
268
|
);
|
184
269
|
};
|
185
270
|
|
271
|
+
|
186
272
|
export const extendSchemaDefinitions = (schema, extended) => {
|
187
273
|
return Object.keys(schema.definitions).reduce(
|
188
274
|
(memo, key) => ({
|
@@ -208,4 +294,4 @@ export const extendSchemaDefinitions = (schema, extended) => {
|
|
208
294
|
}),
|
209
295
|
{},
|
210
296
|
);
|
211
|
-
};
|
297
|
+
};
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@laboratoria/sdk-js",
|
3
|
-
"version": "1.
|
3
|
+
"version": "1.4.0",
|
4
4
|
"description": "Laboratoria JavaScript (browser) SDK",
|
5
5
|
"scripts": {
|
6
6
|
"test": "jest --verbose --coverage",
|
@@ -9,25 +9,25 @@
|
|
9
9
|
"license": "MIT",
|
10
10
|
"dependencies": {
|
11
11
|
"blueimp-md5": "^2.19.0",
|
12
|
-
"firebase": "^9.6.
|
12
|
+
"firebase": "^9.6.6"
|
13
13
|
},
|
14
14
|
"devDependencies": {
|
15
|
-
"@babel/core": "^7.
|
15
|
+
"@babel/core": "^7.17.4",
|
16
16
|
"@babel/plugin-transform-modules-commonjs": "^7.16.8",
|
17
|
-
"babel-jest": "^27.
|
18
|
-
"jest": "^27.
|
19
|
-
"webpack": "^5.
|
17
|
+
"babel-jest": "^27.5.1",
|
18
|
+
"jest": "^27.5.1",
|
19
|
+
"webpack": "^5.69.0",
|
20
20
|
"webpack-cli": "^4.9.2"
|
21
21
|
},
|
22
22
|
"jest": {
|
23
23
|
"testEnvironment": "jsdom",
|
24
24
|
"coverageThreshold": {
|
25
25
|
"global": {
|
26
|
-
"statements": 96,
|
27
|
-
"branches":
|
26
|
+
"statements": 96.9,
|
27
|
+
"branches": 94,
|
28
28
|
"functions": 98,
|
29
|
-
"lines": 96
|
29
|
+
"lines": 96.7
|
30
30
|
}
|
31
31
|
}
|
32
32
|
}
|
33
|
-
}
|
33
|
+
}
|
package/schemas/core.json
CHANGED
@@ -123,6 +123,12 @@
|
|
123
123
|
"$ref": "#/definitions/Contract"
|
124
124
|
}
|
125
125
|
},
|
126
|
+
"contractsAsCheckPilot": {
|
127
|
+
"type": "array",
|
128
|
+
"items": {
|
129
|
+
"$ref": "#/definitions/Contract"
|
130
|
+
}
|
131
|
+
},
|
126
132
|
"gigs": {
|
127
133
|
"type": "array",
|
128
134
|
"items": {
|
@@ -485,30 +491,40 @@
|
|
485
491
|
"isEmployment": {
|
486
492
|
"type": "boolean"
|
487
493
|
},
|
488
|
-
"
|
489
|
-
"type": "
|
490
|
-
"enum": [
|
491
|
-
"BRL",
|
492
|
-
"CLP",
|
493
|
-
"COP",
|
494
|
-
"MXN",
|
495
|
-
"PEN",
|
496
|
-
"USD"
|
497
|
-
]
|
494
|
+
"feeAmount": {
|
495
|
+
"type": "integer"
|
498
496
|
},
|
499
|
-
"
|
500
|
-
"type": "
|
497
|
+
"isTrial": {
|
498
|
+
"type": "boolean",
|
499
|
+
"default": false
|
500
|
+
},
|
501
|
+
"source": {
|
502
|
+
"type": [
|
503
|
+
"string",
|
504
|
+
"null"
|
505
|
+
],
|
501
506
|
"enum": [
|
502
|
-
"
|
503
|
-
"
|
507
|
+
"graduate",
|
508
|
+
"referral",
|
509
|
+
"jazzhr",
|
510
|
+
"web",
|
511
|
+
"linkedin",
|
512
|
+
"other"
|
504
513
|
]
|
505
514
|
},
|
506
|
-
"feeAmount": {
|
507
|
-
"type": "integer"
|
508
|
-
},
|
509
515
|
"user": {
|
510
516
|
"$ref": "#/definitions/User"
|
511
517
|
},
|
518
|
+
"checkPilot": {
|
519
|
+
"anyOf": [
|
520
|
+
{
|
521
|
+
"$ref": "#/definitions/User"
|
522
|
+
},
|
523
|
+
{
|
524
|
+
"type": "null"
|
525
|
+
}
|
526
|
+
]
|
527
|
+
},
|
512
528
|
"country": {
|
513
529
|
"$ref": "#/definitions/Country"
|
514
530
|
},
|
@@ -1,31 +0,0 @@
|
|
1
|
-
# This workflow will do a clean install of node dependencies, cache/restore them, build the source code and run tests across different versions of node
|
2
|
-
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
|
3
|
-
|
4
|
-
name: Node.js CI
|
5
|
-
|
6
|
-
on:
|
7
|
-
push:
|
8
|
-
branches: [ main ]
|
9
|
-
pull_request:
|
10
|
-
branches: [ main ]
|
11
|
-
|
12
|
-
jobs:
|
13
|
-
build:
|
14
|
-
|
15
|
-
runs-on: ubuntu-latest
|
16
|
-
|
17
|
-
strategy:
|
18
|
-
matrix:
|
19
|
-
node-version: [14.x, 16.x]
|
20
|
-
# See supported Node.js release schedule at https://nodejs.org/en/about/releases/
|
21
|
-
|
22
|
-
steps:
|
23
|
-
- uses: actions/checkout@v2
|
24
|
-
- name: Use Node.js ${{ matrix.node-version }}
|
25
|
-
uses: actions/setup-node@v2
|
26
|
-
with:
|
27
|
-
node-version: ${{ matrix.node-version }}
|
28
|
-
cache: 'npm'
|
29
|
-
- run: npm ci
|
30
|
-
- run: npm run build --if-present
|
31
|
-
- run: npm test
|
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 { createAPI as createCoreAPI } from './lib/core';
|
9
|
-
import { createApp } from './index.js';
|
10
|
-
|
11
|
-
jest.mock('./lib/core.js', () => ({
|
12
|
-
createAPI: jest.fn().mockReturnValue({
|
13
|
-
user: {
|
14
|
-
findById: jest.fn().mockResolvedValue({}),
|
15
|
-
},
|
16
|
-
}),
|
17
|
-
}));
|
18
|
-
|
19
|
-
beforeEach(() => {
|
20
|
-
initializeApp.mockClear();
|
21
|
-
onAuthStateChanged.mockClear();
|
22
|
-
signInWithEmailAndPassword.mockClear();
|
23
|
-
});
|
24
|
-
|
25
|
-
describe('createApp', () => {
|
26
|
-
it('should invoke firebase\'s initializaApp', () => {
|
27
|
-
createApp();
|
28
|
-
expect(initializeApp).toHaveBeenCalledTimes(1);
|
29
|
-
expect(initializeApp.mock.calls[0]).toMatchSnapshot();
|
30
|
-
});
|
31
|
-
});
|
32
|
-
|
33
|
-
describe('app.auth.onChange', () => {
|
34
|
-
it('should listen to firebase\'s onAuthStateChanged and notify subscribers when not authenticated', (done) => {
|
35
|
-
const { auth } = createApp();
|
36
|
-
|
37
|
-
onAuthStateChanged.mockImplementationOnce((_, cb) => {
|
38
|
-
cb();
|
39
|
-
return () => { };
|
40
|
-
});
|
41
|
-
|
42
|
-
auth.onChange(({ authUser, user }) => {
|
43
|
-
expect(authUser).toBeNull();
|
44
|
-
expect(user).toBeNull();
|
45
|
-
done();
|
46
|
-
});
|
47
|
-
});
|
48
|
-
|
49
|
-
it('should fetch user from db when authenticated using coreAPI', (done) => {
|
50
|
-
const { auth } = createApp();
|
51
|
-
const mockAuthUser = { uid: 'xxx', getIdToken: () => 'token' };
|
52
|
-
const userMock = { uid: 'xxx', email: 'foo@bar.baz' };
|
53
|
-
|
54
|
-
onAuthStateChanged.mockImplementationOnce((_, cb) => {
|
55
|
-
cb(mockAuthUser);
|
56
|
-
return () => { };
|
57
|
-
});
|
58
|
-
|
59
|
-
createCoreAPI().user.findById.mockResolvedValue(userMock);
|
60
|
-
|
61
|
-
auth.onChange(({ authUser, user }) => {
|
62
|
-
expect(authUser).toEqual(mockAuthUser);
|
63
|
-
expect(user).toEqual(userMock);
|
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
|
-
createCoreAPI().user.findById.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/curriculum.spec.js
DELETED
@@ -1,194 +0,0 @@
|
|
1
|
-
import { createAPI } from './curriculum';
|
2
|
-
|
3
|
-
describe('projects', () => {
|
4
|
-
describe('findMany', () => {
|
5
|
-
// TODO: errores HTTP, GitHub caido, repo borrado, etc...
|
6
|
-
|
7
|
-
it('sends request to get latest version and then corresponding json', () => {
|
8
|
-
global.fetch = jest.fn().mockImplementation(async url => ({
|
9
|
-
status: 200,
|
10
|
-
json: jest.fn().mockResolvedValue(
|
11
|
-
url.startsWith('https://api.')
|
12
|
-
? { tag_name: 'v4.0.0' }
|
13
|
-
: []
|
14
|
-
),
|
15
|
-
}));
|
16
|
-
|
17
|
-
return createAPI().projects.findMany()
|
18
|
-
.then((projects) => {
|
19
|
-
expect(projects).toEqual([]);
|
20
|
-
expect(global.fetch).toHaveBeenCalledTimes(2);
|
21
|
-
expect(global.fetch).toHaveBeenNthCalledWith(
|
22
|
-
1,
|
23
|
-
'https://api.github.com/repos/Laboratoria/bootcamp/releases/latest',
|
24
|
-
);
|
25
|
-
expect(global.fetch).toHaveBeenNthCalledWith(
|
26
|
-
2,
|
27
|
-
'https://raw.githubusercontent.com/Laboratoria/bootcamp/v4.0.0/dist/projects.json',
|
28
|
-
);
|
29
|
-
});
|
30
|
-
});
|
31
|
-
|
32
|
-
it('gets projects in specific tag when passed as option', () => {
|
33
|
-
global.fetch = jest.fn().mockImplementation(async url => ({
|
34
|
-
status: 200,
|
35
|
-
json: jest.fn().mockResolvedValue(
|
36
|
-
url.startsWith('https://api.')
|
37
|
-
? { tag_name: 'v4.0.0' }
|
38
|
-
: []
|
39
|
-
),
|
40
|
-
}));
|
41
|
-
|
42
|
-
return createAPI().projects.findMany({ tag: 'v3.0.0' })
|
43
|
-
.then((projects) => {
|
44
|
-
expect(projects).toEqual([]);
|
45
|
-
expect(global.fetch).toHaveBeenCalledTimes(1);
|
46
|
-
expect(global.fetch).toHaveBeenCalledWith(
|
47
|
-
'https://raw.githubusercontent.com/Laboratoria/bootcamp/v3.0.0/dist/projects.json',
|
48
|
-
);
|
49
|
-
});
|
50
|
-
});
|
51
|
-
|
52
|
-
it('gets projects in specific tag when passed as option', () => {
|
53
|
-
global.fetch = jest.fn().mockImplementation(async url => ({
|
54
|
-
status: 200,
|
55
|
-
json: jest.fn().mockResolvedValue(
|
56
|
-
url.startsWith('https://api.')
|
57
|
-
? { tag_name: 'v4.0.0' }
|
58
|
-
: [
|
59
|
-
{ locale: 'es-ES', track: 'ux' },
|
60
|
-
{ locale: 'es-ES', track: 'js' },
|
61
|
-
{ locale: 'pt-BR', track: 'ux' },
|
62
|
-
]
|
63
|
-
),
|
64
|
-
}));
|
65
|
-
|
66
|
-
return createAPI().projects.findMany({
|
67
|
-
tag: 'v3.0.0',
|
68
|
-
locale: 'es-ES',
|
69
|
-
track: 'ux',
|
70
|
-
})
|
71
|
-
.then((projects) => {
|
72
|
-
expect(projects).toEqual([{ locale: 'es-ES', track: 'ux' }]);
|
73
|
-
expect(global.fetch).toHaveBeenCalledTimes(1);
|
74
|
-
expect(global.fetch).toHaveBeenCalledWith(
|
75
|
-
'https://raw.githubusercontent.com/Laboratoria/bootcamp/v3.0.0/dist/projects.json',
|
76
|
-
);
|
77
|
-
});
|
78
|
-
});
|
79
|
-
|
80
|
-
// it should filter by tag, locale and track...
|
81
|
-
});
|
82
|
-
|
83
|
-
describe('findById', () => {
|
84
|
-
it('sends request to get latest version and then corresponding json', () => {
|
85
|
-
global.fetch = jest.fn().mockImplementation(async url => ({
|
86
|
-
status: 200,
|
87
|
-
json: jest.fn().mockResolvedValue(
|
88
|
-
url.startsWith('https://api.')
|
89
|
-
? { tag_name: 'v4.0.0' }
|
90
|
-
: {}
|
91
|
-
),
|
92
|
-
}));
|
93
|
-
|
94
|
-
return createAPI().projects.findById('cipher')
|
95
|
-
.then((project) => {
|
96
|
-
expect(project).toEqual({});
|
97
|
-
expect(global.fetch).toHaveBeenCalledTimes(2);
|
98
|
-
expect(global.fetch).toHaveBeenNthCalledWith(
|
99
|
-
1,
|
100
|
-
'https://api.github.com/repos/Laboratoria/bootcamp/releases/latest',
|
101
|
-
);
|
102
|
-
expect(global.fetch).toHaveBeenNthCalledWith(
|
103
|
-
2,
|
104
|
-
'https://raw.githubusercontent.com/Laboratoria/bootcamp/v4.0.0/dist/projects/cipher.json',
|
105
|
-
);
|
106
|
-
});
|
107
|
-
});
|
108
|
-
});
|
109
|
-
});
|
110
|
-
|
111
|
-
describe('topics', () => {
|
112
|
-
describe('findMany', () => {
|
113
|
-
it('sends request to get latest version and then corresponding json', () => {
|
114
|
-
global.fetch = jest.fn().mockImplementation(async url => ({
|
115
|
-
status: 200,
|
116
|
-
json: jest.fn().mockResolvedValue(
|
117
|
-
url.startsWith('https://api.')
|
118
|
-
? { tag_name: 'v4.0.0' }
|
119
|
-
: []
|
120
|
-
),
|
121
|
-
}));
|
122
|
-
|
123
|
-
return createAPI().topics.findMany()
|
124
|
-
.then((topics) => {
|
125
|
-
expect(topics).toEqual([]);
|
126
|
-
expect(global.fetch).toHaveBeenCalledTimes(2);
|
127
|
-
expect(global.fetch).toHaveBeenNthCalledWith(
|
128
|
-
1,
|
129
|
-
'https://api.github.com/repos/Laboratoria/bootcamp/releases/latest',
|
130
|
-
);
|
131
|
-
expect(global.fetch).toHaveBeenNthCalledWith(
|
132
|
-
2,
|
133
|
-
'https://raw.githubusercontent.com/Laboratoria/bootcamp/v4.0.0/dist/topics.json',
|
134
|
-
);
|
135
|
-
});
|
136
|
-
});
|
137
|
-
});
|
138
|
-
|
139
|
-
describe('findById', () => {
|
140
|
-
it('sends request to get latest version and then corresponding json', () => {
|
141
|
-
global.fetch = jest.fn().mockImplementation(async url => ({
|
142
|
-
status: 200,
|
143
|
-
json: jest.fn().mockResolvedValue(
|
144
|
-
url.startsWith('https://api.')
|
145
|
-
? { tag_name: 'v4.0.0' }
|
146
|
-
: {}
|
147
|
-
),
|
148
|
-
}));
|
149
|
-
|
150
|
-
return createAPI().topics.findById('javascript')
|
151
|
-
.then((topic) => {
|
152
|
-
expect(topic).toEqual({});
|
153
|
-
expect(global.fetch).toHaveBeenCalledTimes(2);
|
154
|
-
expect(global.fetch).toHaveBeenNthCalledWith(
|
155
|
-
1,
|
156
|
-
'https://api.github.com/repos/Laboratoria/bootcamp/releases/latest',
|
157
|
-
);
|
158
|
-
expect(global.fetch).toHaveBeenNthCalledWith(
|
159
|
-
2,
|
160
|
-
'https://raw.githubusercontent.com/Laboratoria/bootcamp/v4.0.0/dist/topics/javascript.json',
|
161
|
-
);
|
162
|
-
});
|
163
|
-
});
|
164
|
-
});
|
165
|
-
});
|
166
|
-
|
167
|
-
describe('learningObjectives', () => {
|
168
|
-
describe('findMany', () => {
|
169
|
-
it('sends request to get latest version and then corresponding json', () => {
|
170
|
-
global.fetch = jest.fn().mockImplementation(async url => ({
|
171
|
-
status: 200,
|
172
|
-
json: jest.fn().mockResolvedValue(
|
173
|
-
url.startsWith('https://api.')
|
174
|
-
? { tag_name: 'v4.0.0' }
|
175
|
-
: []
|
176
|
-
),
|
177
|
-
}));
|
178
|
-
|
179
|
-
return createAPI().learningObjectives.findMany()
|
180
|
-
.then((learningObjectives) => {
|
181
|
-
expect(learningObjectives).toEqual([]);
|
182
|
-
expect(global.fetch).toHaveBeenCalledTimes(2);
|
183
|
-
expect(global.fetch).toHaveBeenNthCalledWith(
|
184
|
-
1,
|
185
|
-
'https://api.github.com/repos/Laboratoria/bootcamp/releases/latest',
|
186
|
-
);
|
187
|
-
expect(global.fetch).toHaveBeenNthCalledWith(
|
188
|
-
2,
|
189
|
-
'https://raw.githubusercontent.com/Laboratoria/bootcamp/v4.0.0/dist/learning-objectives.json',
|
190
|
-
);
|
191
|
-
});
|
192
|
-
});
|
193
|
-
});
|
194
|
-
});
|
package/lib/model.spec.js
DELETED
@@ -1,242 +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
|
-
it('should exclude null values for optional relation props', async () => {
|
83
|
-
const client = createClient().mockResolvedValue({});
|
84
|
-
const schema = {
|
85
|
-
properties: {
|
86
|
-
signupCohort: {
|
87
|
-
anyOf: [
|
88
|
-
{ '$ref': '#/definitions/Cohort' },
|
89
|
-
{ type: 'null' },
|
90
|
-
],
|
91
|
-
},
|
92
|
-
},
|
93
|
-
};
|
94
|
-
const model = createModel('http://1.2.3.4', {}, 'foo', schema);
|
95
|
-
expect(await model.update({
|
96
|
-
where: { id: 1 },
|
97
|
-
data: { signupCohort: null },
|
98
|
-
})).toEqual({});
|
99
|
-
expect(client).toHaveBeenCalledTimes(1);
|
100
|
-
expect(client).toHaveBeenCalledWith('/foo/1', {
|
101
|
-
body: {
|
102
|
-
where: { id: 1 },
|
103
|
-
data: {},
|
104
|
-
},
|
105
|
-
method: 'PUT',
|
106
|
-
});
|
107
|
-
});
|
108
|
-
});
|
109
|
-
|
110
|
-
describe('model.upsert(options)', () => {
|
111
|
-
it('should send POST request when new row', async () => {
|
112
|
-
const client = createClient().mockResolvedValue({});
|
113
|
-
const model = createModel('http://1.2.3.4', {}, 'foo');
|
114
|
-
const result = await model.upsert({
|
115
|
-
where: {},
|
116
|
-
create: { ok: true },
|
117
|
-
});
|
118
|
-
expect(result).toEqual({});
|
119
|
-
expect(client).toHaveBeenCalledTimes(1);
|
120
|
-
expect(client).toHaveBeenCalledWith('/foo', {
|
121
|
-
body: { data: { ok: true } },
|
122
|
-
method: 'POST',
|
123
|
-
});
|
124
|
-
});
|
125
|
-
|
126
|
-
it('should send PUT request when existing row', async () => {
|
127
|
-
const client = createClient().mockResolvedValue({});
|
128
|
-
const model = createModel('http://1.2.3.4', {}, 'foo');
|
129
|
-
const result = await model.upsert({
|
130
|
-
where: { id: 1 },
|
131
|
-
update: { ok: true },
|
132
|
-
});
|
133
|
-
expect(result).toEqual({});
|
134
|
-
expect(client).toHaveBeenCalledTimes(1);
|
135
|
-
expect(client).toHaveBeenCalledWith('/foo/1', {
|
136
|
-
body: {
|
137
|
-
where: { id: 1 },
|
138
|
-
data: { ok: true },
|
139
|
-
},
|
140
|
-
method: 'PUT',
|
141
|
-
});
|
142
|
-
});
|
143
|
-
});
|
144
|
-
|
145
|
-
describe('model.delete(id)', () => {
|
146
|
-
it('should send POST request', async () => {
|
147
|
-
const client = createClient().mockResolvedValue({});
|
148
|
-
const model = createModel('http://1.2.3.4', {}, 'foo');
|
149
|
-
expect(await model.delete(1)).toEqual({});
|
150
|
-
expect(client).toHaveBeenCalledTimes(1);
|
151
|
-
expect(client).toHaveBeenCalledWith('/foo/1', {
|
152
|
-
method: 'DELETE',
|
153
|
-
});
|
154
|
-
});
|
155
|
-
});
|
156
|
-
|
157
|
-
describe('model.validateAttr(key, value)', () => {
|
158
|
-
it('should not validate when no schema', () => {
|
159
|
-
const model = createModel('http://1.2.3.4', {}, 'foo');
|
160
|
-
expect(model.validateAttr('a', 1)).toBeUndefined();
|
161
|
-
});
|
162
|
-
|
163
|
-
it('should validate text when required', () => {
|
164
|
-
const schema = {
|
165
|
-
properties: {
|
166
|
-
a: { type: 'string' },
|
167
|
-
},
|
168
|
-
};
|
169
|
-
const model = createModel('http://1.2.3.4', {}, 'foo', schema);
|
170
|
-
expect(model.validateAttr('a', '')).toBe('Field is required');
|
171
|
-
});
|
172
|
-
|
173
|
-
it('should validate number when required', () => {
|
174
|
-
const schema = {
|
175
|
-
properties: {
|
176
|
-
a: { type: 'integer', required: true },
|
177
|
-
},
|
178
|
-
};
|
179
|
-
const model = createModel('http://1.2.3.4', {}, 'foo', schema);
|
180
|
-
expect(model.validateAttr('a', 'foo')).toBe('Invalid number format');
|
181
|
-
});
|
182
|
-
|
183
|
-
it('should validate enum', () => {
|
184
|
-
const schema = {
|
185
|
-
properties: {
|
186
|
-
a: { type: 'integer', enum: [1, 2, 3] },
|
187
|
-
},
|
188
|
-
};
|
189
|
-
const model = createModel('http://1.2.3.4', {}, 'foo', schema);
|
190
|
-
expect(model.validateAttr('a', 'foo')).toBe('foo is not one of: 1,2,3');
|
191
|
-
});
|
192
|
-
|
193
|
-
it('should allow empty enum when not required', () => {
|
194
|
-
const schema = {
|
195
|
-
properties: {
|
196
|
-
a: { type: ['integer', 'null'], enum: [1, 2, 3] },
|
197
|
-
},
|
198
|
-
};
|
199
|
-
const model = createModel('http://1.2.3.4', {}, 'foo', schema);
|
200
|
-
expect(model.validateAttr('a', null)).toBeUndefined();
|
201
|
-
expect(model.validateAttr('a', undefined)).toBeUndefined();
|
202
|
-
expect(model.validateAttr('a', '')).toBeUndefined();
|
203
|
-
});
|
204
|
-
});
|
205
|
-
|
206
|
-
describe('model.validate(attributes)', () => {
|
207
|
-
it('should not validate when no schema', () => {
|
208
|
-
const model = createModel('http://1.2.3.4', {}, 'foo');
|
209
|
-
expect(model.validate({ a: 1 })).toEqual({});
|
210
|
-
});
|
211
|
-
|
212
|
-
it('should validate when schema present', () => {
|
213
|
-
const schema = {
|
214
|
-
properties: {
|
215
|
-
a: { type: 'string' },
|
216
|
-
b: { type: 'integer' },
|
217
|
-
},
|
218
|
-
};
|
219
|
-
const model = createModel('http://1.2.3.4', {}, 'foo', schema);
|
220
|
-
expect(model.validate({ a: '', b: 1 })).toEqual({ a: 'Field is required' });
|
221
|
-
});
|
222
|
-
|
223
|
-
it('should validate number when required', () => {
|
224
|
-
const schema = {
|
225
|
-
properties: {
|
226
|
-
a: { type: 'integer' },
|
227
|
-
},
|
228
|
-
};
|
229
|
-
const model = createModel('http://1.2.3.4', {}, 'foo', schema);
|
230
|
-
expect(model.validateAttr('a', 'foo')).toBe('Invalid number format');
|
231
|
-
});
|
232
|
-
|
233
|
-
it('should validate enum', () => {
|
234
|
-
const schema = {
|
235
|
-
properties: {
|
236
|
-
a: { type: 'integer', enum: [1, 2, 3] },
|
237
|
-
},
|
238
|
-
};
|
239
|
-
const model = createModel('http://1.2.3.4', {}, 'foo', schema);
|
240
|
-
expect(model.validateAttr('a', 'foo')).toBe('foo is not one of: 1,2,3');
|
241
|
-
});
|
242
|
-
});
|