@bedrockio/model 0.1.0 → 0.1.1
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 +24 -0
- package/dist/cjs/access.js +4 -0
- package/dist/cjs/assign.js +2 -3
- package/dist/cjs/disallowed.js +40 -0
- package/dist/cjs/include.js +3 -2
- package/dist/cjs/load.js +15 -3
- package/dist/cjs/schema.js +29 -12
- package/dist/cjs/search.js +16 -16
- package/dist/cjs/serialization.js +2 -3
- package/dist/cjs/soft-delete.js +234 -55
- package/dist/cjs/testing.js +8 -0
- package/dist/cjs/validation.js +109 -43
- package/package.json +9 -7
- package/src/access.js +3 -0
- package/src/disallowed.js +63 -0
- package/src/include.js +1 -0
- package/src/load.js +12 -1
- package/src/schema.js +25 -5
- package/src/search.js +21 -10
- package/src/soft-delete.js +238 -85
- package/src/testing.js +7 -0
- package/src/validation.js +134 -43
- package/types/access.d.ts +7 -0
- package/types/access.d.ts.map +1 -0
- package/types/assign.d.ts +2 -0
- package/types/assign.d.ts.map +1 -0
- package/types/const.d.ts +9 -0
- package/types/const.d.ts.map +1 -0
- package/types/disallowed.d.ts +2 -0
- package/types/disallowed.d.ts.map +1 -0
- package/types/errors.d.ts +9 -0
- package/types/errors.d.ts.map +1 -0
- package/types/include.d.ts +4 -0
- package/types/include.d.ts.map +1 -0
- package/types/index.d.ts +6 -0
- package/types/index.d.ts.map +1 -0
- package/types/load.d.ts +15 -0
- package/types/load.d.ts.map +1 -0
- package/types/references.d.ts +2 -0
- package/types/references.d.ts.map +1 -0
- package/types/schema.d.ts +71 -0
- package/types/schema.d.ts.map +1 -0
- package/types/search.d.ts +303 -0
- package/types/search.d.ts.map +1 -0
- package/types/serialization.d.ts +6 -0
- package/types/serialization.d.ts.map +1 -0
- package/types/slug.d.ts +2 -0
- package/types/slug.d.ts.map +1 -0
- package/types/soft-delete.d.ts +4 -0
- package/types/soft-delete.d.ts.map +1 -0
- package/types/testing.d.ts +11 -0
- package/types/testing.d.ts.map +1 -0
- package/types/utils.d.ts +8 -0
- package/types/utils.d.ts.map +1 -0
- package/types/validation.d.ts +13 -0
- package/types/validation.d.ts.map +1 -0
- package/types/warn.d.ts +2 -0
- package/types/warn.d.ts.map +1 -0
- package/babel.config.cjs +0 -41
- package/jest.config.js +0 -8
- package/test/assign.test.js +0 -225
- package/test/definitions/custom-model.json +0 -9
- package/test/definitions/special-category.json +0 -18
- package/test/include.test.js +0 -896
- package/test/load.test.js +0 -47
- package/test/references.test.js +0 -71
- package/test/schema.test.js +0 -919
- package/test/search.test.js +0 -652
- package/test/serialization.test.js +0 -748
- package/test/setup.js +0 -27
- package/test/slug.test.js +0 -112
- package/test/soft-delete.test.js +0 -333
- package/test/validation.test.js +0 -1925
package/test/validation.test.js
DELETED
|
@@ -1,1925 +0,0 @@
|
|
|
1
|
-
import yd from '@bedrockio/yada';
|
|
2
|
-
import { lowerFirst } from 'lodash';
|
|
3
|
-
|
|
4
|
-
import {
|
|
5
|
-
getValidationSchema,
|
|
6
|
-
getNamedValidator,
|
|
7
|
-
addValidators,
|
|
8
|
-
} from '../src/validation';
|
|
9
|
-
import { createTestModel } from '../src/testing';
|
|
10
|
-
|
|
11
|
-
async function assertPass(schema, obj, expected, options) {
|
|
12
|
-
try {
|
|
13
|
-
const result = await schema.validate(obj, options);
|
|
14
|
-
if (expected) {
|
|
15
|
-
expect(result).toEqual(expected);
|
|
16
|
-
} else {
|
|
17
|
-
expect(true).toBe(true);
|
|
18
|
-
}
|
|
19
|
-
} catch (error) {
|
|
20
|
-
// eslint-disable-next-line
|
|
21
|
-
console.error(error);
|
|
22
|
-
throw error;
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
async function assertFail(schema, obj, options) {
|
|
27
|
-
try {
|
|
28
|
-
await schema.validate(obj, options);
|
|
29
|
-
throw new Error('Expected failure but passed.');
|
|
30
|
-
} catch (error) {
|
|
31
|
-
if (!error.details) {
|
|
32
|
-
throw error;
|
|
33
|
-
}
|
|
34
|
-
expect(error).not.toBeUndefined();
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
function assertPassOptions(schema, obj, options) {
|
|
39
|
-
assertPass(schema, obj, undefined, options);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function assertFailOptions(schema, obj, options) {
|
|
43
|
-
assertFail(schema, obj, undefined, options);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
describe('validation', () => {
|
|
47
|
-
describe('getCreateValidation', () => {
|
|
48
|
-
it('should get a basic create schema', async () => {
|
|
49
|
-
const User = createTestModel({
|
|
50
|
-
name: {
|
|
51
|
-
type: 'String',
|
|
52
|
-
required: true,
|
|
53
|
-
},
|
|
54
|
-
count: {
|
|
55
|
-
type: 'Number',
|
|
56
|
-
required: true,
|
|
57
|
-
},
|
|
58
|
-
});
|
|
59
|
-
const schema = User.getCreateValidation();
|
|
60
|
-
expect(yd.isSchema(schema)).toBe(true);
|
|
61
|
-
await assertPass(schema, {
|
|
62
|
-
name: 'foo',
|
|
63
|
-
count: 10,
|
|
64
|
-
});
|
|
65
|
-
await assertFail(schema, {
|
|
66
|
-
name: 'foo',
|
|
67
|
-
});
|
|
68
|
-
await assertFail(schema, {
|
|
69
|
-
name: 10,
|
|
70
|
-
count: 10,
|
|
71
|
-
});
|
|
72
|
-
await assertFail(schema, {
|
|
73
|
-
foo: 'bar',
|
|
74
|
-
});
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
it('should append schemas', async () => {
|
|
78
|
-
const User = createTestModel({
|
|
79
|
-
name: {
|
|
80
|
-
type: 'String',
|
|
81
|
-
required: true,
|
|
82
|
-
},
|
|
83
|
-
});
|
|
84
|
-
const schema = User.getCreateValidation({
|
|
85
|
-
count: yd.number().required(),
|
|
86
|
-
});
|
|
87
|
-
expect(yd.isSchema(schema)).toBe(true);
|
|
88
|
-
await assertFail(schema, {
|
|
89
|
-
name: 'foo',
|
|
90
|
-
});
|
|
91
|
-
await assertPass(schema, {
|
|
92
|
-
name: 'foo',
|
|
93
|
-
count: 10,
|
|
94
|
-
});
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
it('should handle location schema', async () => {
|
|
98
|
-
const User = createTestModel({
|
|
99
|
-
location: {
|
|
100
|
-
type: {
|
|
101
|
-
type: 'String',
|
|
102
|
-
default: 'Point',
|
|
103
|
-
},
|
|
104
|
-
coordinates: {
|
|
105
|
-
type: ['Number'],
|
|
106
|
-
},
|
|
107
|
-
},
|
|
108
|
-
});
|
|
109
|
-
const schema = User.getCreateValidation();
|
|
110
|
-
await assertPass(schema, {
|
|
111
|
-
location: {
|
|
112
|
-
type: 'Line',
|
|
113
|
-
coordinates: [35, 95],
|
|
114
|
-
},
|
|
115
|
-
});
|
|
116
|
-
await assertFail(schema, {
|
|
117
|
-
location: 'Line',
|
|
118
|
-
});
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
it('should not require a field with a default', async () => {
|
|
122
|
-
const User = createTestModel({
|
|
123
|
-
name: {
|
|
124
|
-
type: 'String',
|
|
125
|
-
required: true,
|
|
126
|
-
},
|
|
127
|
-
type: {
|
|
128
|
-
type: 'String',
|
|
129
|
-
required: true,
|
|
130
|
-
enum: ['foo', 'bar'],
|
|
131
|
-
default: 'foo',
|
|
132
|
-
},
|
|
133
|
-
});
|
|
134
|
-
const schema = User.getCreateValidation();
|
|
135
|
-
expect(yd.isSchema(schema)).toBe(true);
|
|
136
|
-
await assertPass(schema, {
|
|
137
|
-
name: 'foo',
|
|
138
|
-
});
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
describe('write access', () => {
|
|
142
|
-
it('should deny access', async () => {
|
|
143
|
-
const User = createTestModel({
|
|
144
|
-
name: 'String',
|
|
145
|
-
verified: {
|
|
146
|
-
type: 'Boolean',
|
|
147
|
-
writeAccess: 'none',
|
|
148
|
-
},
|
|
149
|
-
});
|
|
150
|
-
const schema = User.getCreateValidation();
|
|
151
|
-
await assertPass(schema, {
|
|
152
|
-
name: 'Barry',
|
|
153
|
-
});
|
|
154
|
-
await assertFail(schema, {
|
|
155
|
-
name: 'Barry',
|
|
156
|
-
verified: true,
|
|
157
|
-
});
|
|
158
|
-
await assertFail(schema, {
|
|
159
|
-
verified: false,
|
|
160
|
-
});
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
it('should deny access to an array field', async () => {
|
|
164
|
-
const User = createTestModel({
|
|
165
|
-
name: 'String',
|
|
166
|
-
tokens: {
|
|
167
|
-
type: ['String'],
|
|
168
|
-
writeAccess: 'none',
|
|
169
|
-
},
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
const schema = User.getCreateValidation();
|
|
173
|
-
await assertPass(schema, {
|
|
174
|
-
name: 'Barry',
|
|
175
|
-
});
|
|
176
|
-
await assertFail(schema, {
|
|
177
|
-
name: 'Barry',
|
|
178
|
-
tokens: ['fake token'],
|
|
179
|
-
});
|
|
180
|
-
await assertFail(schema, {
|
|
181
|
-
name: 'Barry',
|
|
182
|
-
tokens: [],
|
|
183
|
-
});
|
|
184
|
-
});
|
|
185
|
-
|
|
186
|
-
it('should deny access on a deep field', async () => {
|
|
187
|
-
const User = createTestModel({
|
|
188
|
-
name: 'String',
|
|
189
|
-
a: {
|
|
190
|
-
b: {
|
|
191
|
-
c: {
|
|
192
|
-
type: 'String',
|
|
193
|
-
writeAccess: 'none',
|
|
194
|
-
},
|
|
195
|
-
},
|
|
196
|
-
},
|
|
197
|
-
});
|
|
198
|
-
const schema = User.getCreateValidation();
|
|
199
|
-
await assertPass(schema, {
|
|
200
|
-
name: 'Barry',
|
|
201
|
-
});
|
|
202
|
-
await assertFail(schema, {
|
|
203
|
-
name: 'Barry',
|
|
204
|
-
a: {
|
|
205
|
-
b: {
|
|
206
|
-
c: 'deep',
|
|
207
|
-
},
|
|
208
|
-
},
|
|
209
|
-
});
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
it('should deny access by scope', async () => {
|
|
213
|
-
const User = createTestModel({
|
|
214
|
-
name: 'String',
|
|
215
|
-
password: {
|
|
216
|
-
type: 'String',
|
|
217
|
-
writeAccess: ['admin'],
|
|
218
|
-
},
|
|
219
|
-
});
|
|
220
|
-
const schema = User.getCreateValidation();
|
|
221
|
-
await assertPass(schema, {
|
|
222
|
-
name: 'Barry',
|
|
223
|
-
});
|
|
224
|
-
await assertFail(schema, {
|
|
225
|
-
name: 'Barry',
|
|
226
|
-
password: 'fake password',
|
|
227
|
-
});
|
|
228
|
-
await assertPassOptions(
|
|
229
|
-
schema,
|
|
230
|
-
{
|
|
231
|
-
name: 'Barry',
|
|
232
|
-
password: 'fake password',
|
|
233
|
-
},
|
|
234
|
-
{ scope: 'admin' }
|
|
235
|
-
);
|
|
236
|
-
});
|
|
237
|
-
|
|
238
|
-
it('should require only one valid scope', async () => {
|
|
239
|
-
const User = createTestModel({
|
|
240
|
-
foo: {
|
|
241
|
-
type: 'String',
|
|
242
|
-
writeAccess: ['foo'],
|
|
243
|
-
},
|
|
244
|
-
bar: {
|
|
245
|
-
type: 'String',
|
|
246
|
-
writeAccess: ['bar'],
|
|
247
|
-
},
|
|
248
|
-
foobar: {
|
|
249
|
-
type: 'String',
|
|
250
|
-
writeAccess: ['foo', 'bar'],
|
|
251
|
-
},
|
|
252
|
-
});
|
|
253
|
-
const schema = User.getCreateValidation();
|
|
254
|
-
|
|
255
|
-
// With ['foo'] scopes
|
|
256
|
-
await assertPassOptions(
|
|
257
|
-
schema,
|
|
258
|
-
{
|
|
259
|
-
foo: 'foo!',
|
|
260
|
-
},
|
|
261
|
-
{ scopes: ['foo'] }
|
|
262
|
-
);
|
|
263
|
-
await assertFailOptions(
|
|
264
|
-
schema,
|
|
265
|
-
{
|
|
266
|
-
bar: 'bar!',
|
|
267
|
-
},
|
|
268
|
-
{ scopes: ['foo'] }
|
|
269
|
-
);
|
|
270
|
-
await assertPassOptions(
|
|
271
|
-
schema,
|
|
272
|
-
{
|
|
273
|
-
foobar: 'foobar!',
|
|
274
|
-
},
|
|
275
|
-
{ scopes: ['foo'] }
|
|
276
|
-
);
|
|
277
|
-
await assertPassOptions(
|
|
278
|
-
schema,
|
|
279
|
-
{
|
|
280
|
-
foo: 'foo!',
|
|
281
|
-
foobar: 'foobar!',
|
|
282
|
-
},
|
|
283
|
-
{ scopes: ['foo'] }
|
|
284
|
-
);
|
|
285
|
-
await assertFailOptions(
|
|
286
|
-
schema,
|
|
287
|
-
{
|
|
288
|
-
foo: 'foo!',
|
|
289
|
-
bar: 'bar!',
|
|
290
|
-
foobar: 'foobar!',
|
|
291
|
-
},
|
|
292
|
-
{ scopes: ['foo'] }
|
|
293
|
-
);
|
|
294
|
-
|
|
295
|
-
// With ['bar'] scopes
|
|
296
|
-
await assertFailOptions(
|
|
297
|
-
schema,
|
|
298
|
-
{
|
|
299
|
-
foo: 'foo!',
|
|
300
|
-
},
|
|
301
|
-
{ scopes: ['bar'] }
|
|
302
|
-
);
|
|
303
|
-
await assertPassOptions(
|
|
304
|
-
schema,
|
|
305
|
-
{
|
|
306
|
-
bar: 'bar!',
|
|
307
|
-
},
|
|
308
|
-
{ scopes: ['bar'] }
|
|
309
|
-
);
|
|
310
|
-
await assertPassOptions(
|
|
311
|
-
schema,
|
|
312
|
-
{
|
|
313
|
-
foobar: 'foobar!',
|
|
314
|
-
},
|
|
315
|
-
{ scopes: ['bar'] }
|
|
316
|
-
);
|
|
317
|
-
await assertFailOptions(
|
|
318
|
-
schema,
|
|
319
|
-
{
|
|
320
|
-
foo: 'foo!',
|
|
321
|
-
foobar: 'foobar!',
|
|
322
|
-
},
|
|
323
|
-
{ scopes: ['bar'] }
|
|
324
|
-
);
|
|
325
|
-
await assertFailOptions(
|
|
326
|
-
schema,
|
|
327
|
-
{
|
|
328
|
-
foo: 'foo!',
|
|
329
|
-
bar: 'bar!',
|
|
330
|
-
foobar: 'foobar!',
|
|
331
|
-
},
|
|
332
|
-
{ scopes: ['bar'] }
|
|
333
|
-
);
|
|
334
|
-
|
|
335
|
-
// With ['foo', 'bar'] scopes
|
|
336
|
-
await assertPassOptions(
|
|
337
|
-
schema,
|
|
338
|
-
{
|
|
339
|
-
foo: 'foo!',
|
|
340
|
-
},
|
|
341
|
-
{ scopes: ['foo', 'bar'] }
|
|
342
|
-
);
|
|
343
|
-
await assertPassOptions(
|
|
344
|
-
schema,
|
|
345
|
-
{
|
|
346
|
-
bar: 'bar!',
|
|
347
|
-
},
|
|
348
|
-
{ scopes: ['foo', 'bar'] }
|
|
349
|
-
);
|
|
350
|
-
await assertPassOptions(
|
|
351
|
-
schema,
|
|
352
|
-
{
|
|
353
|
-
foobar: 'foobar!',
|
|
354
|
-
},
|
|
355
|
-
{ scopes: ['foo', 'bar'] }
|
|
356
|
-
);
|
|
357
|
-
await assertPassOptions(
|
|
358
|
-
schema,
|
|
359
|
-
{
|
|
360
|
-
foo: 'foo!',
|
|
361
|
-
foobar: 'foobar!',
|
|
362
|
-
},
|
|
363
|
-
{ scopes: ['foo', 'bar'] }
|
|
364
|
-
);
|
|
365
|
-
await assertPassOptions(
|
|
366
|
-
schema,
|
|
367
|
-
{
|
|
368
|
-
foo: 'foo!',
|
|
369
|
-
bar: 'bar!',
|
|
370
|
-
foobar: 'foobar!',
|
|
371
|
-
},
|
|
372
|
-
{ scopes: ['foo', 'bar'] }
|
|
373
|
-
);
|
|
374
|
-
});
|
|
375
|
-
|
|
376
|
-
it('should skip field entirely if no write access', async () => {
|
|
377
|
-
const User = createTestModel({
|
|
378
|
-
name: 'String',
|
|
379
|
-
apiKey: {
|
|
380
|
-
type: 'String',
|
|
381
|
-
required: true,
|
|
382
|
-
writeAccess: 'none',
|
|
383
|
-
},
|
|
384
|
-
});
|
|
385
|
-
const schema = User.getCreateValidation();
|
|
386
|
-
await assertPass(schema, {
|
|
387
|
-
name: 'Barry',
|
|
388
|
-
});
|
|
389
|
-
await assertFail(schema, {
|
|
390
|
-
name: 'Barry',
|
|
391
|
-
apiKey: 'foo',
|
|
392
|
-
});
|
|
393
|
-
});
|
|
394
|
-
});
|
|
395
|
-
});
|
|
396
|
-
|
|
397
|
-
describe('getUpdateValidation', () => {
|
|
398
|
-
it('should not fail on empty object', async () => {
|
|
399
|
-
const User = createTestModel({
|
|
400
|
-
name: 'String',
|
|
401
|
-
});
|
|
402
|
-
const schema = User.getUpdateValidation();
|
|
403
|
-
await assertPass(schema, {});
|
|
404
|
-
});
|
|
405
|
-
|
|
406
|
-
it('should skip unknown in nested validations', async () => {
|
|
407
|
-
const User = createTestModel({
|
|
408
|
-
names: [
|
|
409
|
-
{
|
|
410
|
-
first: 'String',
|
|
411
|
-
},
|
|
412
|
-
],
|
|
413
|
-
});
|
|
414
|
-
const schema = User.getUpdateValidation();
|
|
415
|
-
await assertPass(schema, {
|
|
416
|
-
names: [
|
|
417
|
-
{
|
|
418
|
-
id: 'fake id',
|
|
419
|
-
first: 'First',
|
|
420
|
-
},
|
|
421
|
-
],
|
|
422
|
-
});
|
|
423
|
-
});
|
|
424
|
-
|
|
425
|
-
it('should skip required fields', async () => {
|
|
426
|
-
const User = createTestModel({
|
|
427
|
-
name: {
|
|
428
|
-
type: 'String',
|
|
429
|
-
required: true,
|
|
430
|
-
},
|
|
431
|
-
count: {
|
|
432
|
-
type: 'Number',
|
|
433
|
-
required: true,
|
|
434
|
-
},
|
|
435
|
-
});
|
|
436
|
-
const schema = User.getUpdateValidation();
|
|
437
|
-
expect(yd.isSchema(schema)).toBe(true);
|
|
438
|
-
await assertPass(schema, {
|
|
439
|
-
name: 'foo',
|
|
440
|
-
});
|
|
441
|
-
await assertPass(schema, {
|
|
442
|
-
count: 10,
|
|
443
|
-
});
|
|
444
|
-
});
|
|
445
|
-
|
|
446
|
-
it('should not enforce a schema on unstructured objects', async () => {
|
|
447
|
-
const User = createTestModel({
|
|
448
|
-
profile: {
|
|
449
|
-
name: 'String',
|
|
450
|
-
},
|
|
451
|
-
devices: [
|
|
452
|
-
{
|
|
453
|
-
type: 'Object',
|
|
454
|
-
},
|
|
455
|
-
],
|
|
456
|
-
});
|
|
457
|
-
const schema = User.getUpdateValidation();
|
|
458
|
-
expect(yd.isSchema(schema)).toBe(true);
|
|
459
|
-
await assertPass(schema, {
|
|
460
|
-
devices: [
|
|
461
|
-
{
|
|
462
|
-
id: 'id',
|
|
463
|
-
name: 'name',
|
|
464
|
-
class: 'class',
|
|
465
|
-
},
|
|
466
|
-
],
|
|
467
|
-
});
|
|
468
|
-
await assertPass(schema, {
|
|
469
|
-
profile: {
|
|
470
|
-
name: 'foo',
|
|
471
|
-
},
|
|
472
|
-
devices: [
|
|
473
|
-
{
|
|
474
|
-
id: 'id',
|
|
475
|
-
name: 'name',
|
|
476
|
-
class: 'class',
|
|
477
|
-
},
|
|
478
|
-
],
|
|
479
|
-
});
|
|
480
|
-
|
|
481
|
-
const result = await schema.validate({
|
|
482
|
-
profile: {
|
|
483
|
-
name: 'name',
|
|
484
|
-
foo: 'bar',
|
|
485
|
-
},
|
|
486
|
-
devices: [
|
|
487
|
-
{
|
|
488
|
-
id: 'id',
|
|
489
|
-
name: 'name',
|
|
490
|
-
class: 'class',
|
|
491
|
-
},
|
|
492
|
-
],
|
|
493
|
-
});
|
|
494
|
-
expect(result).toEqual({
|
|
495
|
-
profile: {
|
|
496
|
-
name: 'name',
|
|
497
|
-
},
|
|
498
|
-
devices: [
|
|
499
|
-
{
|
|
500
|
-
id: 'id',
|
|
501
|
-
name: 'name',
|
|
502
|
-
class: 'class',
|
|
503
|
-
},
|
|
504
|
-
],
|
|
505
|
-
});
|
|
506
|
-
});
|
|
507
|
-
|
|
508
|
-
it('should strip reserved fields', async () => {
|
|
509
|
-
const User = createTestModel({
|
|
510
|
-
name: {
|
|
511
|
-
type: 'String',
|
|
512
|
-
required: true,
|
|
513
|
-
},
|
|
514
|
-
});
|
|
515
|
-
const schema = User.getUpdateValidation();
|
|
516
|
-
await assertPass(schema, {
|
|
517
|
-
name: 'foo',
|
|
518
|
-
id: 'id',
|
|
519
|
-
createdAt: 'createdAt',
|
|
520
|
-
updatedAt: 'updatedAt',
|
|
521
|
-
deletedAt: 'deletedAt',
|
|
522
|
-
});
|
|
523
|
-
});
|
|
524
|
-
|
|
525
|
-
it('should strip virtuals', async () => {
|
|
526
|
-
const User = createTestModel({
|
|
527
|
-
firstName: {
|
|
528
|
-
type: 'String',
|
|
529
|
-
required: true,
|
|
530
|
-
},
|
|
531
|
-
lastName: {
|
|
532
|
-
type: 'String',
|
|
533
|
-
required: true,
|
|
534
|
-
},
|
|
535
|
-
});
|
|
536
|
-
User.schema.virtual('fullName').get(function () {
|
|
537
|
-
return `${this.firstName} ${this.lastName}`;
|
|
538
|
-
});
|
|
539
|
-
const user = new User({
|
|
540
|
-
firstName: 'John',
|
|
541
|
-
lastName: 'Doe',
|
|
542
|
-
});
|
|
543
|
-
const data = user.toObject();
|
|
544
|
-
expect(data).toEqual({
|
|
545
|
-
id: user.id,
|
|
546
|
-
firstName: 'John',
|
|
547
|
-
lastName: 'Doe',
|
|
548
|
-
fullName: 'John Doe',
|
|
549
|
-
});
|
|
550
|
-
const schema = User.getUpdateValidation();
|
|
551
|
-
await assertPass(schema, data);
|
|
552
|
-
expect(await schema.validate(data)).toEqual({
|
|
553
|
-
firstName: 'John',
|
|
554
|
-
lastName: 'Doe',
|
|
555
|
-
});
|
|
556
|
-
});
|
|
557
|
-
|
|
558
|
-
it('should strip nested virtuals', async () => {
|
|
559
|
-
const Profile = createTestModel({
|
|
560
|
-
firstName: {
|
|
561
|
-
type: 'String',
|
|
562
|
-
required: true,
|
|
563
|
-
},
|
|
564
|
-
lastName: {
|
|
565
|
-
type: 'String',
|
|
566
|
-
required: true,
|
|
567
|
-
},
|
|
568
|
-
});
|
|
569
|
-
Profile.schema.virtual('fullName').get(function () {
|
|
570
|
-
return `${this.firstName} ${this.lastName}`;
|
|
571
|
-
});
|
|
572
|
-
const User = createTestModel({
|
|
573
|
-
profile: Profile.schema,
|
|
574
|
-
});
|
|
575
|
-
const user = new User({
|
|
576
|
-
profile: {
|
|
577
|
-
firstName: 'John',
|
|
578
|
-
lastName: 'Doe',
|
|
579
|
-
},
|
|
580
|
-
});
|
|
581
|
-
const data = user.toObject();
|
|
582
|
-
expect(data).toEqual({
|
|
583
|
-
id: user.id,
|
|
584
|
-
profile: {
|
|
585
|
-
id: user.profile.id,
|
|
586
|
-
firstName: 'John',
|
|
587
|
-
lastName: 'Doe',
|
|
588
|
-
fullName: 'John Doe',
|
|
589
|
-
},
|
|
590
|
-
});
|
|
591
|
-
const schema = User.getUpdateValidation();
|
|
592
|
-
await assertPass(schema, data);
|
|
593
|
-
expect(await schema.validate(data)).toEqual({
|
|
594
|
-
profile: {
|
|
595
|
-
firstName: 'John',
|
|
596
|
-
lastName: 'Doe',
|
|
597
|
-
},
|
|
598
|
-
});
|
|
599
|
-
});
|
|
600
|
-
|
|
601
|
-
it('should not skip required validations in array fields', async () => {
|
|
602
|
-
const User = createTestModel({
|
|
603
|
-
users: [
|
|
604
|
-
{
|
|
605
|
-
name: {
|
|
606
|
-
type: 'String',
|
|
607
|
-
required: true,
|
|
608
|
-
},
|
|
609
|
-
count: 'Number',
|
|
610
|
-
},
|
|
611
|
-
],
|
|
612
|
-
});
|
|
613
|
-
const schema = User.getUpdateValidation();
|
|
614
|
-
expect(yd.isSchema(schema)).toBe(true);
|
|
615
|
-
await assertPass(schema, {
|
|
616
|
-
users: [
|
|
617
|
-
{
|
|
618
|
-
name: 'foo',
|
|
619
|
-
},
|
|
620
|
-
],
|
|
621
|
-
});
|
|
622
|
-
await assertPass(schema, {
|
|
623
|
-
users: [
|
|
624
|
-
{
|
|
625
|
-
name: 'foo',
|
|
626
|
-
count: 1,
|
|
627
|
-
},
|
|
628
|
-
],
|
|
629
|
-
});
|
|
630
|
-
await assertFail(schema, {
|
|
631
|
-
users: [{}],
|
|
632
|
-
});
|
|
633
|
-
await assertFail(schema, {
|
|
634
|
-
users: [
|
|
635
|
-
{
|
|
636
|
-
count: 1,
|
|
637
|
-
},
|
|
638
|
-
],
|
|
639
|
-
});
|
|
640
|
-
});
|
|
641
|
-
|
|
642
|
-
describe('write access', () => {
|
|
643
|
-
it('should strip field on attempt to update with no write scopes', async () => {
|
|
644
|
-
const User = createTestModel({
|
|
645
|
-
name: 'String',
|
|
646
|
-
password: {
|
|
647
|
-
type: 'String',
|
|
648
|
-
writeAccess: 'none',
|
|
649
|
-
},
|
|
650
|
-
});
|
|
651
|
-
const schema = User.getUpdateValidation();
|
|
652
|
-
await assertPass(
|
|
653
|
-
schema,
|
|
654
|
-
{
|
|
655
|
-
name: 'Barry',
|
|
656
|
-
password: 'fake password',
|
|
657
|
-
},
|
|
658
|
-
{
|
|
659
|
-
name: 'Barry',
|
|
660
|
-
}
|
|
661
|
-
);
|
|
662
|
-
});
|
|
663
|
-
|
|
664
|
-
it('should throw on attempt to update with invalid scopes', async () => {
|
|
665
|
-
const User = createTestModel({
|
|
666
|
-
name: 'String',
|
|
667
|
-
password: {
|
|
668
|
-
type: 'String',
|
|
669
|
-
writeAccess: 'admin',
|
|
670
|
-
},
|
|
671
|
-
});
|
|
672
|
-
const schema = User.getUpdateValidation();
|
|
673
|
-
await expect(
|
|
674
|
-
schema.validate(
|
|
675
|
-
{
|
|
676
|
-
name: 'Barry',
|
|
677
|
-
password: 'fake password',
|
|
678
|
-
},
|
|
679
|
-
{
|
|
680
|
-
scope: 'not admin',
|
|
681
|
-
}
|
|
682
|
-
)
|
|
683
|
-
).rejects.toThrow();
|
|
684
|
-
});
|
|
685
|
-
|
|
686
|
-
it('should not throw when value has not changed', async () => {
|
|
687
|
-
const User = createTestModel({
|
|
688
|
-
name: {
|
|
689
|
-
type: 'String',
|
|
690
|
-
writeAccess: 'admin',
|
|
691
|
-
},
|
|
692
|
-
profile: {
|
|
693
|
-
age: {
|
|
694
|
-
type: 'Number',
|
|
695
|
-
writeAccess: 'admin',
|
|
696
|
-
},
|
|
697
|
-
},
|
|
698
|
-
});
|
|
699
|
-
const user = await User.create({
|
|
700
|
-
name: 'Joe',
|
|
701
|
-
profile: {
|
|
702
|
-
age: 30,
|
|
703
|
-
},
|
|
704
|
-
});
|
|
705
|
-
const schema = User.getUpdateValidation();
|
|
706
|
-
|
|
707
|
-
await expect(
|
|
708
|
-
schema.validate(
|
|
709
|
-
{
|
|
710
|
-
name: 'Joe',
|
|
711
|
-
},
|
|
712
|
-
{
|
|
713
|
-
document: user,
|
|
714
|
-
}
|
|
715
|
-
)
|
|
716
|
-
).resolves.not.toThrow();
|
|
717
|
-
|
|
718
|
-
await expect(
|
|
719
|
-
schema.validate(
|
|
720
|
-
{
|
|
721
|
-
profile: {
|
|
722
|
-
age: 30,
|
|
723
|
-
},
|
|
724
|
-
},
|
|
725
|
-
{
|
|
726
|
-
document: user,
|
|
727
|
-
}
|
|
728
|
-
)
|
|
729
|
-
).resolves.not.toThrow();
|
|
730
|
-
|
|
731
|
-
await expect(
|
|
732
|
-
schema.validate(
|
|
733
|
-
{
|
|
734
|
-
name: 'Joe',
|
|
735
|
-
profile: {
|
|
736
|
-
age: 30,
|
|
737
|
-
},
|
|
738
|
-
},
|
|
739
|
-
{
|
|
740
|
-
document: user,
|
|
741
|
-
}
|
|
742
|
-
)
|
|
743
|
-
).resolves.not.toThrow();
|
|
744
|
-
|
|
745
|
-
await expect(
|
|
746
|
-
schema.validate(
|
|
747
|
-
{
|
|
748
|
-
name: 'Bill',
|
|
749
|
-
},
|
|
750
|
-
{
|
|
751
|
-
document: user,
|
|
752
|
-
}
|
|
753
|
-
)
|
|
754
|
-
).rejects.toThrow();
|
|
755
|
-
|
|
756
|
-
await expect(
|
|
757
|
-
schema.validate(
|
|
758
|
-
{
|
|
759
|
-
profile: {
|
|
760
|
-
age: 50,
|
|
761
|
-
},
|
|
762
|
-
},
|
|
763
|
-
{
|
|
764
|
-
document: user,
|
|
765
|
-
}
|
|
766
|
-
)
|
|
767
|
-
).rejects.toThrow();
|
|
768
|
-
});
|
|
769
|
-
|
|
770
|
-
it('should handle self scope', async () => {
|
|
771
|
-
const User = createTestModel({
|
|
772
|
-
name: 'String',
|
|
773
|
-
grade: {
|
|
774
|
-
type: 'Number',
|
|
775
|
-
writeAccess: 'self',
|
|
776
|
-
},
|
|
777
|
-
});
|
|
778
|
-
const user1 = await User.create({
|
|
779
|
-
name: 'Barry',
|
|
780
|
-
});
|
|
781
|
-
const user2 = await User.create({
|
|
782
|
-
name: 'Larry',
|
|
783
|
-
});
|
|
784
|
-
const schema = User.getCreateValidation();
|
|
785
|
-
|
|
786
|
-
await expect(
|
|
787
|
-
schema.validate(
|
|
788
|
-
{
|
|
789
|
-
name: 'Barry',
|
|
790
|
-
grade: 50,
|
|
791
|
-
},
|
|
792
|
-
{
|
|
793
|
-
document: user1,
|
|
794
|
-
authUser: user1,
|
|
795
|
-
}
|
|
796
|
-
)
|
|
797
|
-
).resolves.not.toThrow();
|
|
798
|
-
|
|
799
|
-
await expect(
|
|
800
|
-
schema.validate(
|
|
801
|
-
{
|
|
802
|
-
name: 'Barry',
|
|
803
|
-
grade: 50,
|
|
804
|
-
},
|
|
805
|
-
{
|
|
806
|
-
document: user1,
|
|
807
|
-
authUser: user2,
|
|
808
|
-
}
|
|
809
|
-
)
|
|
810
|
-
).rejects.toThrow();
|
|
811
|
-
});
|
|
812
|
-
|
|
813
|
-
it('should resolve from the model name', async () => {
|
|
814
|
-
const User = createTestModel({
|
|
815
|
-
name: 'String',
|
|
816
|
-
grade: {
|
|
817
|
-
type: 'Number',
|
|
818
|
-
writeAccess: 'self',
|
|
819
|
-
},
|
|
820
|
-
});
|
|
821
|
-
const user = await User.create({
|
|
822
|
-
name: 'Barry',
|
|
823
|
-
});
|
|
824
|
-
const schema = User.getCreateValidation();
|
|
825
|
-
|
|
826
|
-
await expect(
|
|
827
|
-
schema.validate(
|
|
828
|
-
{
|
|
829
|
-
name: 'Barry',
|
|
830
|
-
grade: 50,
|
|
831
|
-
},
|
|
832
|
-
{
|
|
833
|
-
[lowerFirst(User.modelName)]: user,
|
|
834
|
-
authUser: user,
|
|
835
|
-
}
|
|
836
|
-
)
|
|
837
|
-
).resolves.not.toThrow();
|
|
838
|
-
});
|
|
839
|
-
|
|
840
|
-
it('should throw if not the same', async () => {
|
|
841
|
-
const User = createTestModel({
|
|
842
|
-
name: 'String',
|
|
843
|
-
grade: {
|
|
844
|
-
type: 'Number',
|
|
845
|
-
writeAccess: 'self',
|
|
846
|
-
},
|
|
847
|
-
});
|
|
848
|
-
const user1 = await User.create({
|
|
849
|
-
name: 'Barry',
|
|
850
|
-
grade: 50,
|
|
851
|
-
});
|
|
852
|
-
const user2 = await User.create({
|
|
853
|
-
name: 'Larry',
|
|
854
|
-
grade: 50,
|
|
855
|
-
});
|
|
856
|
-
const schema = User.getCreateValidation();
|
|
857
|
-
|
|
858
|
-
await expect(
|
|
859
|
-
schema.validate(
|
|
860
|
-
{
|
|
861
|
-
name: 'Barry',
|
|
862
|
-
grade: 50,
|
|
863
|
-
},
|
|
864
|
-
{
|
|
865
|
-
document: user1,
|
|
866
|
-
authUser: user1,
|
|
867
|
-
}
|
|
868
|
-
)
|
|
869
|
-
).resolves.not.toThrow();
|
|
870
|
-
|
|
871
|
-
await expect(
|
|
872
|
-
schema.validate(
|
|
873
|
-
{
|
|
874
|
-
name: 'Barry',
|
|
875
|
-
grade: 50,
|
|
876
|
-
},
|
|
877
|
-
{
|
|
878
|
-
document: user1,
|
|
879
|
-
authUser: user2,
|
|
880
|
-
}
|
|
881
|
-
)
|
|
882
|
-
).resolves.not.toThrow();
|
|
883
|
-
|
|
884
|
-
await expect(
|
|
885
|
-
schema.validate(
|
|
886
|
-
{
|
|
887
|
-
name: 'Barry',
|
|
888
|
-
grade: 70,
|
|
889
|
-
},
|
|
890
|
-
{
|
|
891
|
-
document: user1,
|
|
892
|
-
authUser: user2,
|
|
893
|
-
}
|
|
894
|
-
)
|
|
895
|
-
).rejects.toThrow();
|
|
896
|
-
});
|
|
897
|
-
});
|
|
898
|
-
});
|
|
899
|
-
|
|
900
|
-
describe('getSearchValidation', () => {
|
|
901
|
-
it('should get a basic search schema allowing empty', async () => {
|
|
902
|
-
const User = createTestModel({
|
|
903
|
-
name: {
|
|
904
|
-
type: 'String',
|
|
905
|
-
required: true,
|
|
906
|
-
},
|
|
907
|
-
});
|
|
908
|
-
const schema = User.getSearchValidation();
|
|
909
|
-
expect(yd.isSchema(schema)).toBe(true);
|
|
910
|
-
await assertPass(schema, {
|
|
911
|
-
name: 'foo',
|
|
912
|
-
});
|
|
913
|
-
await assertPass(schema, {});
|
|
914
|
-
});
|
|
915
|
-
|
|
916
|
-
it('should mixin default search schema', async () => {
|
|
917
|
-
const User = createTestModel({
|
|
918
|
-
name: {
|
|
919
|
-
type: 'String',
|
|
920
|
-
required: true,
|
|
921
|
-
},
|
|
922
|
-
});
|
|
923
|
-
const schema = User.getSearchValidation();
|
|
924
|
-
await assertPass(schema, {
|
|
925
|
-
name: 'foo',
|
|
926
|
-
keyword: 'keyword',
|
|
927
|
-
skip: 1,
|
|
928
|
-
limit: 5,
|
|
929
|
-
sort: {
|
|
930
|
-
field: 'createdAt',
|
|
931
|
-
order: 'desc',
|
|
932
|
-
},
|
|
933
|
-
ids: ['6345a7f52773f7001d97c0d2'],
|
|
934
|
-
});
|
|
935
|
-
|
|
936
|
-
await assertFail(schema, {
|
|
937
|
-
ids: ['12345'],
|
|
938
|
-
});
|
|
939
|
-
});
|
|
940
|
-
|
|
941
|
-
it('should allow an array for a string field', async () => {
|
|
942
|
-
const User = createTestModel({
|
|
943
|
-
name: {
|
|
944
|
-
type: 'String',
|
|
945
|
-
required: true,
|
|
946
|
-
},
|
|
947
|
-
});
|
|
948
|
-
const schema = User.getSearchValidation();
|
|
949
|
-
expect(yd.isSchema(schema)).toBe(true);
|
|
950
|
-
await assertPass(schema, {
|
|
951
|
-
name: ['foo', 'bar'],
|
|
952
|
-
});
|
|
953
|
-
await assertPass(schema, {});
|
|
954
|
-
});
|
|
955
|
-
|
|
956
|
-
it('should allow range based search', async () => {
|
|
957
|
-
const User = createTestModel({
|
|
958
|
-
age: 'Number',
|
|
959
|
-
date: 'Date',
|
|
960
|
-
});
|
|
961
|
-
const schema = User.getSearchValidation();
|
|
962
|
-
expect(yd.isSchema(schema)).toBe(true);
|
|
963
|
-
await assertPass(schema, {
|
|
964
|
-
age: { gte: 5 },
|
|
965
|
-
});
|
|
966
|
-
await assertPass(schema, {
|
|
967
|
-
date: { gte: '2020-01-01' },
|
|
968
|
-
});
|
|
969
|
-
await assertPass(schema, {});
|
|
970
|
-
});
|
|
971
|
-
|
|
972
|
-
it('should unwind array fields', async () => {
|
|
973
|
-
const User = createTestModel({
|
|
974
|
-
tokens: ['String'],
|
|
975
|
-
});
|
|
976
|
-
const schema = User.getSearchValidation();
|
|
977
|
-
await assertPass(schema, {
|
|
978
|
-
tokens: 'foo',
|
|
979
|
-
});
|
|
980
|
-
});
|
|
981
|
-
|
|
982
|
-
it('should allow search on a nested field', async () => {
|
|
983
|
-
const User = createTestModel({
|
|
984
|
-
roles: [
|
|
985
|
-
{
|
|
986
|
-
role: {
|
|
987
|
-
type: 'String',
|
|
988
|
-
required: true,
|
|
989
|
-
},
|
|
990
|
-
scope: {
|
|
991
|
-
type: 'String',
|
|
992
|
-
required: true,
|
|
993
|
-
},
|
|
994
|
-
},
|
|
995
|
-
],
|
|
996
|
-
});
|
|
997
|
-
const schema = User.getSearchValidation();
|
|
998
|
-
await assertPass(schema, {
|
|
999
|
-
roles: {
|
|
1000
|
-
role: 'test',
|
|
1001
|
-
},
|
|
1002
|
-
});
|
|
1003
|
-
});
|
|
1004
|
-
|
|
1005
|
-
it('should allow an array to be passed for sort', async () => {
|
|
1006
|
-
const User = createTestModel({
|
|
1007
|
-
name: 'String',
|
|
1008
|
-
});
|
|
1009
|
-
const schema = User.getSearchValidation();
|
|
1010
|
-
expect(yd.isSchema(schema)).toBe(true);
|
|
1011
|
-
await assertPass(schema, {
|
|
1012
|
-
name: 'foo',
|
|
1013
|
-
sort: [
|
|
1014
|
-
{
|
|
1015
|
-
field: 'name',
|
|
1016
|
-
order: 'asc',
|
|
1017
|
-
},
|
|
1018
|
-
{
|
|
1019
|
-
field: 'createdAt',
|
|
1020
|
-
order: 'desc',
|
|
1021
|
-
},
|
|
1022
|
-
],
|
|
1023
|
-
});
|
|
1024
|
-
});
|
|
1025
|
-
|
|
1026
|
-
describe('write access', () => {
|
|
1027
|
-
it('should not enforce write access', async () => {
|
|
1028
|
-
const User = createTestModel({
|
|
1029
|
-
name: 'String',
|
|
1030
|
-
age: {
|
|
1031
|
-
type: 'Number',
|
|
1032
|
-
writeAccess: 'none',
|
|
1033
|
-
},
|
|
1034
|
-
});
|
|
1035
|
-
const schema = User.getSearchValidation();
|
|
1036
|
-
await assertPass(schema, {
|
|
1037
|
-
name: 'Barry',
|
|
1038
|
-
});
|
|
1039
|
-
await assertPass(schema, {
|
|
1040
|
-
name: 'Barry',
|
|
1041
|
-
age: 50,
|
|
1042
|
-
});
|
|
1043
|
-
});
|
|
1044
|
-
|
|
1045
|
-
it('should enforce read access', async () => {
|
|
1046
|
-
const User = createTestModel({
|
|
1047
|
-
name: 'String',
|
|
1048
|
-
age: {
|
|
1049
|
-
type: 'Number',
|
|
1050
|
-
readAccess: 'none',
|
|
1051
|
-
},
|
|
1052
|
-
});
|
|
1053
|
-
const schema = User.getSearchValidation();
|
|
1054
|
-
await assertPass(schema, {
|
|
1055
|
-
name: 'Barry',
|
|
1056
|
-
});
|
|
1057
|
-
await assertFail(schema, {
|
|
1058
|
-
name: 'Barry',
|
|
1059
|
-
age: 50,
|
|
1060
|
-
});
|
|
1061
|
-
});
|
|
1062
|
-
});
|
|
1063
|
-
|
|
1064
|
-
describe('ranges', () => {
|
|
1065
|
-
it('should append a number range schema', async () => {
|
|
1066
|
-
const User = createTestModel({
|
|
1067
|
-
age: 'Number',
|
|
1068
|
-
});
|
|
1069
|
-
const schema = User.getSearchValidation();
|
|
1070
|
-
await assertPass(schema, { age: 5 });
|
|
1071
|
-
await assertPass(schema, { age: { lte: 5 } });
|
|
1072
|
-
await assertPass(schema, { age: { gte: 5 } });
|
|
1073
|
-
await assertPass(schema, { age: { gte: 5, lte: 5 } });
|
|
1074
|
-
await assertPass(schema, { age: { lt: 5 } });
|
|
1075
|
-
await assertPass(schema, { age: { gt: 5 } });
|
|
1076
|
-
await assertPass(schema, { age: { gt: 5, lt: 5 } });
|
|
1077
|
-
await assertPass(schema, { age: {} });
|
|
1078
|
-
await assertFail(schema, { age: { lte: 'bad' } });
|
|
1079
|
-
});
|
|
1080
|
-
|
|
1081
|
-
it('should append a date range schema', async () => {
|
|
1082
|
-
const User = createTestModel({
|
|
1083
|
-
startsAt: 'Date',
|
|
1084
|
-
});
|
|
1085
|
-
const schema = User.getSearchValidation();
|
|
1086
|
-
await assertPass(schema, { startsAt: '2020-01-01' });
|
|
1087
|
-
await assertPass(schema, { startsAt: { lte: '2020-01-01' } });
|
|
1088
|
-
await assertPass(schema, { startsAt: { gte: '2019-01-01' } });
|
|
1089
|
-
await assertPass(schema, {
|
|
1090
|
-
startsAt: { gte: '2019-01-01', lte: '2020-01-01' },
|
|
1091
|
-
});
|
|
1092
|
-
await assertPass(schema, { startsAt: { lt: '2020-01-01' } });
|
|
1093
|
-
await assertPass(schema, { startsAt: { gt: '2019-01-01' } });
|
|
1094
|
-
await assertPass(schema, {
|
|
1095
|
-
startsAt: { gt: '2019-01-01', lt: '2020-01-01' },
|
|
1096
|
-
});
|
|
1097
|
-
await assertPass(schema, { startsAt: {} });
|
|
1098
|
-
await assertFail(schema, { startsAt: { lte: 'bad' } });
|
|
1099
|
-
});
|
|
1100
|
-
});
|
|
1101
|
-
});
|
|
1102
|
-
|
|
1103
|
-
it('should allow min/max on fields', async () => {
|
|
1104
|
-
const Review = createTestModel({
|
|
1105
|
-
age: {
|
|
1106
|
-
type: 'Number',
|
|
1107
|
-
min: 0,
|
|
1108
|
-
max: 100,
|
|
1109
|
-
},
|
|
1110
|
-
date: {
|
|
1111
|
-
type: 'Date',
|
|
1112
|
-
min: '2020-01-01',
|
|
1113
|
-
max: '2021-01-01',
|
|
1114
|
-
},
|
|
1115
|
-
});
|
|
1116
|
-
const schema = Review.getSearchValidation();
|
|
1117
|
-
await assertPass(schema, {
|
|
1118
|
-
age: 50,
|
|
1119
|
-
});
|
|
1120
|
-
await assertFail(schema, {
|
|
1121
|
-
age: -50,
|
|
1122
|
-
});
|
|
1123
|
-
await assertFail(schema, {
|
|
1124
|
-
age: 150,
|
|
1125
|
-
});
|
|
1126
|
-
await assertPass(schema, {
|
|
1127
|
-
date: '2020-06-01',
|
|
1128
|
-
});
|
|
1129
|
-
await assertFail(schema, {
|
|
1130
|
-
date: '2019-01-01',
|
|
1131
|
-
});
|
|
1132
|
-
await assertFail(schema, {
|
|
1133
|
-
date: '2022-01-01',
|
|
1134
|
-
});
|
|
1135
|
-
await assertPass(schema, {});
|
|
1136
|
-
});
|
|
1137
|
-
});
|
|
1138
|
-
|
|
1139
|
-
describe('getValidationSchema', () => {
|
|
1140
|
-
describe('alternate type forms', () => {
|
|
1141
|
-
it('should get a schema for a basic string field', async () => {
|
|
1142
|
-
const schema = getValidationSchema({
|
|
1143
|
-
name: 'String',
|
|
1144
|
-
});
|
|
1145
|
-
expect(yd.isSchema(schema)).toBe(true);
|
|
1146
|
-
});
|
|
1147
|
-
|
|
1148
|
-
it('should get a schema for shorthand string field', async () => {
|
|
1149
|
-
const schema = getValidationSchema({
|
|
1150
|
-
name: 'String',
|
|
1151
|
-
});
|
|
1152
|
-
expect(yd.isSchema(schema)).toBe(true);
|
|
1153
|
-
});
|
|
1154
|
-
|
|
1155
|
-
it('should get a schema for string type', async () => {
|
|
1156
|
-
const schema = getValidationSchema({
|
|
1157
|
-
name: 'String',
|
|
1158
|
-
});
|
|
1159
|
-
expect(yd.isSchema(schema)).toBe(true);
|
|
1160
|
-
});
|
|
1161
|
-
|
|
1162
|
-
it('should get a schema for shorthand string type', async () => {
|
|
1163
|
-
const schema = getValidationSchema({
|
|
1164
|
-
name: 'String',
|
|
1165
|
-
});
|
|
1166
|
-
expect(yd.isSchema(schema)).toBe(true);
|
|
1167
|
-
});
|
|
1168
|
-
});
|
|
1169
|
-
|
|
1170
|
-
describe('basic functionality', () => {
|
|
1171
|
-
it('should validate basic fields', async () => {
|
|
1172
|
-
const schema = getValidationSchema({
|
|
1173
|
-
name: {
|
|
1174
|
-
type: 'String',
|
|
1175
|
-
required: true,
|
|
1176
|
-
},
|
|
1177
|
-
count: 'Number',
|
|
1178
|
-
});
|
|
1179
|
-
await assertPass(schema, {
|
|
1180
|
-
name: 'foo',
|
|
1181
|
-
});
|
|
1182
|
-
await assertPass(schema, {
|
|
1183
|
-
name: 'foo',
|
|
1184
|
-
count: 10,
|
|
1185
|
-
});
|
|
1186
|
-
await assertFail(schema, {
|
|
1187
|
-
count: 10,
|
|
1188
|
-
});
|
|
1189
|
-
await assertFail(schema, {});
|
|
1190
|
-
});
|
|
1191
|
-
|
|
1192
|
-
it('should strip unknown fields', async () => {
|
|
1193
|
-
const schema = getValidationSchema(
|
|
1194
|
-
{
|
|
1195
|
-
name: 'String',
|
|
1196
|
-
},
|
|
1197
|
-
{
|
|
1198
|
-
stripUnknown: true,
|
|
1199
|
-
}
|
|
1200
|
-
);
|
|
1201
|
-
await assertPass(schema, { id: 1, name: 'foo' }, { name: 'foo' });
|
|
1202
|
-
await assertPass(schema, { createdAt: 'date', name: 'foo' });
|
|
1203
|
-
await assertPass(schema, { updatedAt: 'date', name: 'foo' });
|
|
1204
|
-
await assertPass(schema, { deletedAt: 'date', name: 'foo' });
|
|
1205
|
-
});
|
|
1206
|
-
|
|
1207
|
-
it('should override required fields', async () => {
|
|
1208
|
-
const schema = getValidationSchema(
|
|
1209
|
-
{
|
|
1210
|
-
name: {
|
|
1211
|
-
type: 'String',
|
|
1212
|
-
required: true,
|
|
1213
|
-
},
|
|
1214
|
-
count: {
|
|
1215
|
-
type: 'Number',
|
|
1216
|
-
required: true,
|
|
1217
|
-
},
|
|
1218
|
-
},
|
|
1219
|
-
{
|
|
1220
|
-
skipRequired: true,
|
|
1221
|
-
}
|
|
1222
|
-
);
|
|
1223
|
-
await assertPass(schema, { name: 'foo' });
|
|
1224
|
-
await assertPass(schema, { count: 5 });
|
|
1225
|
-
await assertPass(schema, {});
|
|
1226
|
-
});
|
|
1227
|
-
|
|
1228
|
-
it('should not skip required inside nested arrays', async () => {
|
|
1229
|
-
const schema = getValidationSchema(
|
|
1230
|
-
{
|
|
1231
|
-
users: [
|
|
1232
|
-
{
|
|
1233
|
-
name: {
|
|
1234
|
-
type: 'String',
|
|
1235
|
-
required: true,
|
|
1236
|
-
},
|
|
1237
|
-
count: 'Number',
|
|
1238
|
-
},
|
|
1239
|
-
],
|
|
1240
|
-
},
|
|
1241
|
-
{
|
|
1242
|
-
skipRequired: true,
|
|
1243
|
-
}
|
|
1244
|
-
);
|
|
1245
|
-
await assertPass(schema, {
|
|
1246
|
-
users: [
|
|
1247
|
-
{
|
|
1248
|
-
name: 'foo',
|
|
1249
|
-
count: 1,
|
|
1250
|
-
},
|
|
1251
|
-
],
|
|
1252
|
-
});
|
|
1253
|
-
await assertPass(schema, {
|
|
1254
|
-
users: [
|
|
1255
|
-
{
|
|
1256
|
-
name: 'foo',
|
|
1257
|
-
},
|
|
1258
|
-
],
|
|
1259
|
-
});
|
|
1260
|
-
await assertPass(schema, {
|
|
1261
|
-
users: [],
|
|
1262
|
-
});
|
|
1263
|
-
await assertFail(schema, {
|
|
1264
|
-
users: [
|
|
1265
|
-
{
|
|
1266
|
-
count: 1,
|
|
1267
|
-
},
|
|
1268
|
-
],
|
|
1269
|
-
});
|
|
1270
|
-
await assertFail(schema, {
|
|
1271
|
-
users: [{}],
|
|
1272
|
-
});
|
|
1273
|
-
});
|
|
1274
|
-
});
|
|
1275
|
-
|
|
1276
|
-
describe('global options', () => {
|
|
1277
|
-
it('should validate a required field', async () => {
|
|
1278
|
-
const schema = getValidationSchema({
|
|
1279
|
-
name: {
|
|
1280
|
-
type: 'String',
|
|
1281
|
-
required: true,
|
|
1282
|
-
},
|
|
1283
|
-
});
|
|
1284
|
-
await assertPass(schema, { name: 'foo' });
|
|
1285
|
-
await assertFail(schema, {});
|
|
1286
|
-
});
|
|
1287
|
-
});
|
|
1288
|
-
|
|
1289
|
-
describe('string fields', () => {
|
|
1290
|
-
it('should validate an enum field', async () => {
|
|
1291
|
-
const schema = getValidationSchema({
|
|
1292
|
-
name: {
|
|
1293
|
-
type: 'String',
|
|
1294
|
-
enum: ['foo', 'bar'],
|
|
1295
|
-
},
|
|
1296
|
-
});
|
|
1297
|
-
await assertPass(schema, { name: 'foo' });
|
|
1298
|
-
await assertPass(schema, { name: 'bar' });
|
|
1299
|
-
await assertFail(schema, { name: 'baz' });
|
|
1300
|
-
});
|
|
1301
|
-
|
|
1302
|
-
it('should optionally allow an array on an enum field', async () => {
|
|
1303
|
-
const schema = getValidationSchema(
|
|
1304
|
-
{
|
|
1305
|
-
name: {
|
|
1306
|
-
type: 'String',
|
|
1307
|
-
enum: ['foo', 'bar'],
|
|
1308
|
-
},
|
|
1309
|
-
},
|
|
1310
|
-
{
|
|
1311
|
-
allowMultiple: true,
|
|
1312
|
-
}
|
|
1313
|
-
);
|
|
1314
|
-
await assertPass(schema, { name: ['foo', 'bar'] });
|
|
1315
|
-
});
|
|
1316
|
-
|
|
1317
|
-
it('should validate minimum length', async () => {
|
|
1318
|
-
const schema = getValidationSchema({
|
|
1319
|
-
name: {
|
|
1320
|
-
type: 'String',
|
|
1321
|
-
minLength: 3,
|
|
1322
|
-
},
|
|
1323
|
-
});
|
|
1324
|
-
await assertPass(schema, { name: 'foo' });
|
|
1325
|
-
await assertFail(schema, { name: 'fo' });
|
|
1326
|
-
});
|
|
1327
|
-
|
|
1328
|
-
it('should validate maximum length', async () => {
|
|
1329
|
-
const schema = getValidationSchema({
|
|
1330
|
-
name: {
|
|
1331
|
-
type: 'String',
|
|
1332
|
-
maxLength: 3,
|
|
1333
|
-
},
|
|
1334
|
-
});
|
|
1335
|
-
await assertPass(schema, { name: 'foo' });
|
|
1336
|
-
await assertFail(schema, { name: 'fooo' });
|
|
1337
|
-
});
|
|
1338
|
-
|
|
1339
|
-
it('should validate minimum and maximum length together', async () => {
|
|
1340
|
-
const schema = getValidationSchema({
|
|
1341
|
-
name: {
|
|
1342
|
-
type: 'String',
|
|
1343
|
-
minLength: 3,
|
|
1344
|
-
maxLength: 5,
|
|
1345
|
-
},
|
|
1346
|
-
});
|
|
1347
|
-
await assertPass(schema, { name: 'foo' });
|
|
1348
|
-
await assertPass(schema, { name: 'fooo' });
|
|
1349
|
-
await assertFail(schema, { name: 'foooooo' });
|
|
1350
|
-
});
|
|
1351
|
-
|
|
1352
|
-
it('should validate a matched field', async () => {
|
|
1353
|
-
const schema = getValidationSchema({
|
|
1354
|
-
name: {
|
|
1355
|
-
type: 'String',
|
|
1356
|
-
match: /^foo$/,
|
|
1357
|
-
},
|
|
1358
|
-
});
|
|
1359
|
-
await assertPass(schema, { name: 'foo' });
|
|
1360
|
-
await assertFail(schema, { name: 'foo ' });
|
|
1361
|
-
});
|
|
1362
|
-
|
|
1363
|
-
it('should convert string match field to regex', async () => {
|
|
1364
|
-
const schema = getValidationSchema({
|
|
1365
|
-
name: {
|
|
1366
|
-
type: 'String',
|
|
1367
|
-
match: '^foo$',
|
|
1368
|
-
},
|
|
1369
|
-
});
|
|
1370
|
-
await assertPass(schema, { name: 'foo' });
|
|
1371
|
-
await assertFail(schema, { name: 'bar' });
|
|
1372
|
-
});
|
|
1373
|
-
});
|
|
1374
|
-
|
|
1375
|
-
describe('number fields', () => {
|
|
1376
|
-
it('should validate an enum field', async () => {
|
|
1377
|
-
const schema = getValidationSchema({
|
|
1378
|
-
count: {
|
|
1379
|
-
type: 'Number',
|
|
1380
|
-
enum: [100, 1000],
|
|
1381
|
-
},
|
|
1382
|
-
});
|
|
1383
|
-
await assertPass(schema, { count: 100 });
|
|
1384
|
-
await assertPass(schema, { count: 1000 });
|
|
1385
|
-
await assertFail(schema, { count: 1001 });
|
|
1386
|
-
});
|
|
1387
|
-
|
|
1388
|
-
it('should validate a minimum value', async () => {
|
|
1389
|
-
const schema = getValidationSchema({
|
|
1390
|
-
count: {
|
|
1391
|
-
type: 'Number',
|
|
1392
|
-
min: 100,
|
|
1393
|
-
},
|
|
1394
|
-
});
|
|
1395
|
-
await assertPass(schema, { count: 100 });
|
|
1396
|
-
await assertFail(schema, { count: 99 });
|
|
1397
|
-
});
|
|
1398
|
-
|
|
1399
|
-
it('should validate maximum value', async () => {
|
|
1400
|
-
const schema = getValidationSchema({
|
|
1401
|
-
count: {
|
|
1402
|
-
type: 'Number',
|
|
1403
|
-
max: 100,
|
|
1404
|
-
},
|
|
1405
|
-
});
|
|
1406
|
-
await assertPass(schema, { count: 100 });
|
|
1407
|
-
await assertFail(schema, { count: 101 });
|
|
1408
|
-
});
|
|
1409
|
-
|
|
1410
|
-
it('should validate minimum and maximum together', async () => {
|
|
1411
|
-
const schema = getValidationSchema({
|
|
1412
|
-
count: {
|
|
1413
|
-
type: 'Number',
|
|
1414
|
-
min: 100,
|
|
1415
|
-
max: 200,
|
|
1416
|
-
},
|
|
1417
|
-
});
|
|
1418
|
-
await assertPass(schema, { count: 100 });
|
|
1419
|
-
await assertPass(schema, { count: 200 });
|
|
1420
|
-
await assertFail(schema, { count: 99 });
|
|
1421
|
-
await assertFail(schema, { count: 201 });
|
|
1422
|
-
});
|
|
1423
|
-
});
|
|
1424
|
-
|
|
1425
|
-
describe('boolean fields', () => {
|
|
1426
|
-
it('should validate boolean field', async () => {
|
|
1427
|
-
const schema = getValidationSchema({
|
|
1428
|
-
isActive: 'Boolean',
|
|
1429
|
-
});
|
|
1430
|
-
await assertPass(schema, { isActive: true });
|
|
1431
|
-
await assertPass(schema, { isActive: false });
|
|
1432
|
-
});
|
|
1433
|
-
});
|
|
1434
|
-
|
|
1435
|
-
describe('date fields', () => {
|
|
1436
|
-
it('should validate date ISO-8601 field', async () => {
|
|
1437
|
-
const schema = getValidationSchema({
|
|
1438
|
-
posted: 'Date',
|
|
1439
|
-
});
|
|
1440
|
-
await assertPass(schema, { posted: '2020-01-01T00:00:00Z' });
|
|
1441
|
-
await assertPass(schema, { posted: '2020-01-01T00:00:00' });
|
|
1442
|
-
await assertFail(schema, { posted: 'January 1, 2020' });
|
|
1443
|
-
});
|
|
1444
|
-
});
|
|
1445
|
-
|
|
1446
|
-
describe('reference fields', () => {
|
|
1447
|
-
describe('simple', () => {
|
|
1448
|
-
it('should validate a string reference field', async () => {
|
|
1449
|
-
const schema = getValidationSchema({
|
|
1450
|
-
image: {
|
|
1451
|
-
type: 'ObjectId',
|
|
1452
|
-
ref: 'Upload',
|
|
1453
|
-
},
|
|
1454
|
-
});
|
|
1455
|
-
await assertPass(schema, { image: '5fd396fac80fa73203bd9554' });
|
|
1456
|
-
await assertFail(schema, { image: 'bad id' });
|
|
1457
|
-
});
|
|
1458
|
-
|
|
1459
|
-
it('should transform an object with a valid id', async () => {
|
|
1460
|
-
const schema = getValidationSchema({
|
|
1461
|
-
image: {
|
|
1462
|
-
type: 'ObjectId',
|
|
1463
|
-
ref: 'Upload',
|
|
1464
|
-
},
|
|
1465
|
-
});
|
|
1466
|
-
await assertPass(schema, { image: '5fd396fac80fa73203bd9554' });
|
|
1467
|
-
await assertPass(schema, { image: { id: '5fd396fac80fa73203bd9554' } });
|
|
1468
|
-
await assertFail(schema, { image: { id: '5fd396fac80fa73203bd9xyz' } });
|
|
1469
|
-
await assertFail(schema, { image: { id: '5fd396fac80f' } });
|
|
1470
|
-
await assertFail(schema, { image: { id: 'bad id' } });
|
|
1471
|
-
await assertFail(schema, { image: { id: '' } });
|
|
1472
|
-
});
|
|
1473
|
-
|
|
1474
|
-
it('should transform an array of objects or ids', async () => {
|
|
1475
|
-
const schema = getValidationSchema({
|
|
1476
|
-
categories: [
|
|
1477
|
-
{
|
|
1478
|
-
type: 'ObjectId',
|
|
1479
|
-
ref: 'Upload',
|
|
1480
|
-
},
|
|
1481
|
-
],
|
|
1482
|
-
});
|
|
1483
|
-
await assertPass(schema, { categories: ['5fd396fac80fa73203bd9554'] });
|
|
1484
|
-
await assertPass(schema, {
|
|
1485
|
-
categories: [{ id: '5fd396fac80fa73203bd9554' }],
|
|
1486
|
-
});
|
|
1487
|
-
await assertPass(schema, {
|
|
1488
|
-
categories: [
|
|
1489
|
-
'5fd396fac80fa73203bd9554',
|
|
1490
|
-
{ id: '5fd396fac80fa73203bd9554' },
|
|
1491
|
-
'5fd396fac80fa73203bd9554',
|
|
1492
|
-
{ id: '5fd396fac80fa73203bd9554' },
|
|
1493
|
-
'5fd396fac80fa73203bd9554',
|
|
1494
|
-
],
|
|
1495
|
-
});
|
|
1496
|
-
await assertFail(schema, {
|
|
1497
|
-
categories: [{ id: '5fd396fac80fa73203bd9554' }, 'bad id'],
|
|
1498
|
-
});
|
|
1499
|
-
await assertFail(schema, {
|
|
1500
|
-
categories: [{ id: '5fd396fac80fa73203bd9xyz' }],
|
|
1501
|
-
});
|
|
1502
|
-
await assertFail(schema, { categories: [{ id: '5fd396fac80f' }] });
|
|
1503
|
-
await assertFail(schema, { categories: [{ id: 'bad id' }] });
|
|
1504
|
-
await assertFail(schema, { categories: [{ id: '' }] });
|
|
1505
|
-
});
|
|
1506
|
-
});
|
|
1507
|
-
|
|
1508
|
-
describe('nested', () => {
|
|
1509
|
-
it('should transform a deeply nested ObjectId', async () => {
|
|
1510
|
-
const schema = getValidationSchema({
|
|
1511
|
-
user: {
|
|
1512
|
-
manager: {
|
|
1513
|
-
category: {
|
|
1514
|
-
type: 'ObjectId',
|
|
1515
|
-
ref: 'Upload',
|
|
1516
|
-
},
|
|
1517
|
-
},
|
|
1518
|
-
},
|
|
1519
|
-
});
|
|
1520
|
-
await assertPass(schema, {
|
|
1521
|
-
user: {
|
|
1522
|
-
manager: {
|
|
1523
|
-
category: '5fd396fac80fa73203bd9554',
|
|
1524
|
-
},
|
|
1525
|
-
},
|
|
1526
|
-
});
|
|
1527
|
-
await assertPass(schema, {
|
|
1528
|
-
user: {
|
|
1529
|
-
manager: {
|
|
1530
|
-
category: {
|
|
1531
|
-
id: '5fd396fac80fa73203bd9554',
|
|
1532
|
-
},
|
|
1533
|
-
},
|
|
1534
|
-
},
|
|
1535
|
-
});
|
|
1536
|
-
await assertFail(schema, {
|
|
1537
|
-
user: {
|
|
1538
|
-
manager: {
|
|
1539
|
-
category: {
|
|
1540
|
-
id: {
|
|
1541
|
-
id: '5fd396fac80fa73203bd9554',
|
|
1542
|
-
},
|
|
1543
|
-
},
|
|
1544
|
-
},
|
|
1545
|
-
},
|
|
1546
|
-
});
|
|
1547
|
-
await assertFail(schema, {
|
|
1548
|
-
user: {
|
|
1549
|
-
manager: {
|
|
1550
|
-
id: '5fd396fac80fa73203bd9554',
|
|
1551
|
-
},
|
|
1552
|
-
},
|
|
1553
|
-
});
|
|
1554
|
-
await assertFail(schema, {
|
|
1555
|
-
user: {
|
|
1556
|
-
id: '5fd396fac80fa73203bd9554',
|
|
1557
|
-
},
|
|
1558
|
-
});
|
|
1559
|
-
await assertFail(schema, {
|
|
1560
|
-
id: '5fd396fac80fa73203bd9554',
|
|
1561
|
-
});
|
|
1562
|
-
await assertPass(schema, {});
|
|
1563
|
-
});
|
|
1564
|
-
|
|
1565
|
-
it('should transform a deeply nested array ObjectId', async () => {
|
|
1566
|
-
const schema = getValidationSchema({
|
|
1567
|
-
users: [
|
|
1568
|
-
{
|
|
1569
|
-
managers: [
|
|
1570
|
-
{
|
|
1571
|
-
categories: [
|
|
1572
|
-
{
|
|
1573
|
-
type: 'ObjectId',
|
|
1574
|
-
ref: 'Upload',
|
|
1575
|
-
},
|
|
1576
|
-
],
|
|
1577
|
-
},
|
|
1578
|
-
],
|
|
1579
|
-
},
|
|
1580
|
-
],
|
|
1581
|
-
});
|
|
1582
|
-
await assertPass(schema, {
|
|
1583
|
-
users: [
|
|
1584
|
-
{
|
|
1585
|
-
managers: [
|
|
1586
|
-
{
|
|
1587
|
-
categories: ['5fd396fac80fa73203bd9554'],
|
|
1588
|
-
},
|
|
1589
|
-
],
|
|
1590
|
-
},
|
|
1591
|
-
],
|
|
1592
|
-
});
|
|
1593
|
-
await assertPass(schema, {
|
|
1594
|
-
users: [
|
|
1595
|
-
{
|
|
1596
|
-
managers: [
|
|
1597
|
-
{
|
|
1598
|
-
categories: [
|
|
1599
|
-
{
|
|
1600
|
-
id: '5fd396fac80fa73203bd9554',
|
|
1601
|
-
},
|
|
1602
|
-
],
|
|
1603
|
-
},
|
|
1604
|
-
],
|
|
1605
|
-
},
|
|
1606
|
-
],
|
|
1607
|
-
});
|
|
1608
|
-
await assertFail(schema, {
|
|
1609
|
-
users: [
|
|
1610
|
-
{
|
|
1611
|
-
manager: [
|
|
1612
|
-
{
|
|
1613
|
-
categories: [
|
|
1614
|
-
{
|
|
1615
|
-
id: {
|
|
1616
|
-
id: '5fd396fac80fa73203bd9554',
|
|
1617
|
-
},
|
|
1618
|
-
},
|
|
1619
|
-
],
|
|
1620
|
-
},
|
|
1621
|
-
],
|
|
1622
|
-
},
|
|
1623
|
-
],
|
|
1624
|
-
});
|
|
1625
|
-
await assertFail(schema, {
|
|
1626
|
-
users: [
|
|
1627
|
-
{
|
|
1628
|
-
managers: [
|
|
1629
|
-
{
|
|
1630
|
-
id: '5fd396fac80fa73203bd9554',
|
|
1631
|
-
},
|
|
1632
|
-
],
|
|
1633
|
-
},
|
|
1634
|
-
],
|
|
1635
|
-
});
|
|
1636
|
-
await assertFail(schema, {
|
|
1637
|
-
users: [
|
|
1638
|
-
{
|
|
1639
|
-
id: '5fd396fac80fa73203bd9554',
|
|
1640
|
-
},
|
|
1641
|
-
],
|
|
1642
|
-
});
|
|
1643
|
-
await assertFail(schema, {
|
|
1644
|
-
id: '5fd396fac80fa73203bd9554',
|
|
1645
|
-
});
|
|
1646
|
-
await assertPass(schema, {});
|
|
1647
|
-
});
|
|
1648
|
-
});
|
|
1649
|
-
});
|
|
1650
|
-
|
|
1651
|
-
describe('array fields', () => {
|
|
1652
|
-
it('should validate array of strings', async () => {
|
|
1653
|
-
const schema = getValidationSchema({
|
|
1654
|
-
categories: ['String'],
|
|
1655
|
-
});
|
|
1656
|
-
await assertPass(schema, { categories: ['foo'] });
|
|
1657
|
-
await assertPass(schema, { categories: [] });
|
|
1658
|
-
await assertFail(schema, { categories: 'foo' });
|
|
1659
|
-
});
|
|
1660
|
-
|
|
1661
|
-
it('should validate array type shortcut syntax', async () => {
|
|
1662
|
-
const schema = getValidationSchema({
|
|
1663
|
-
categories: ['String'],
|
|
1664
|
-
});
|
|
1665
|
-
await assertPass(schema, { categories: ['foo'] });
|
|
1666
|
-
await assertPass(schema, { categories: [] });
|
|
1667
|
-
await assertFail(schema, { categories: 'foo' });
|
|
1668
|
-
});
|
|
1669
|
-
|
|
1670
|
-
it('should validate array of object ids', async () => {
|
|
1671
|
-
const schema = getValidationSchema({
|
|
1672
|
-
categories: [
|
|
1673
|
-
{
|
|
1674
|
-
type: 'ObjectId',
|
|
1675
|
-
},
|
|
1676
|
-
],
|
|
1677
|
-
});
|
|
1678
|
-
await assertPass(schema, { categories: ['5fd396fac80fa73203bd9554'] });
|
|
1679
|
-
await assertPass(schema, { categories: [] });
|
|
1680
|
-
await assertFail(schema, { categories: ['bad id'] });
|
|
1681
|
-
});
|
|
1682
|
-
|
|
1683
|
-
it('should validate min/max elements in an array field', async () => {
|
|
1684
|
-
const schema = getValidationSchema({
|
|
1685
|
-
categories: {
|
|
1686
|
-
type: ['String'],
|
|
1687
|
-
minLength: 1,
|
|
1688
|
-
maxLength: 2,
|
|
1689
|
-
},
|
|
1690
|
-
});
|
|
1691
|
-
await assertFail(schema, { categories: [] });
|
|
1692
|
-
await assertPass(schema, { categories: ['foo'] });
|
|
1693
|
-
await assertPass(schema, { categories: ['foo', 'bar'] });
|
|
1694
|
-
await assertFail(schema, { categories: ['foo', 'bar', 'baz'] });
|
|
1695
|
-
});
|
|
1696
|
-
|
|
1697
|
-
it('should validate nested object array', async () => {
|
|
1698
|
-
const schema = getValidationSchema({
|
|
1699
|
-
roles: [
|
|
1700
|
-
{
|
|
1701
|
-
role: {
|
|
1702
|
-
type: 'String',
|
|
1703
|
-
required: true,
|
|
1704
|
-
},
|
|
1705
|
-
scope: {
|
|
1706
|
-
type: 'String',
|
|
1707
|
-
required: true,
|
|
1708
|
-
},
|
|
1709
|
-
scopeRef: {
|
|
1710
|
-
type: 'ObjectId',
|
|
1711
|
-
},
|
|
1712
|
-
},
|
|
1713
|
-
],
|
|
1714
|
-
});
|
|
1715
|
-
await assertPass(schema, {
|
|
1716
|
-
roles: [
|
|
1717
|
-
{
|
|
1718
|
-
role: 'role',
|
|
1719
|
-
scope: 'scope',
|
|
1720
|
-
},
|
|
1721
|
-
],
|
|
1722
|
-
});
|
|
1723
|
-
await assertPass(schema, {
|
|
1724
|
-
roles: [
|
|
1725
|
-
{
|
|
1726
|
-
role: 'role1',
|
|
1727
|
-
scope: 'scope',
|
|
1728
|
-
},
|
|
1729
|
-
{
|
|
1730
|
-
role: 'role2',
|
|
1731
|
-
scope: 'scope',
|
|
1732
|
-
},
|
|
1733
|
-
],
|
|
1734
|
-
});
|
|
1735
|
-
await assertPass(schema, {
|
|
1736
|
-
roles: [
|
|
1737
|
-
{
|
|
1738
|
-
role: 'role',
|
|
1739
|
-
scope: 'scope',
|
|
1740
|
-
scopeRef: '60096760d392ed3ba949265d',
|
|
1741
|
-
},
|
|
1742
|
-
],
|
|
1743
|
-
});
|
|
1744
|
-
await assertFail(schema, {
|
|
1745
|
-
roles: [
|
|
1746
|
-
{
|
|
1747
|
-
role: 'role',
|
|
1748
|
-
},
|
|
1749
|
-
],
|
|
1750
|
-
});
|
|
1751
|
-
await assertFail(schema, {
|
|
1752
|
-
roles: [
|
|
1753
|
-
{
|
|
1754
|
-
scope: 'scope',
|
|
1755
|
-
},
|
|
1756
|
-
],
|
|
1757
|
-
});
|
|
1758
|
-
});
|
|
1759
|
-
|
|
1760
|
-
it('should validate on array of strings', async () => {
|
|
1761
|
-
const schema = getValidationSchema({
|
|
1762
|
-
tags: ['String'],
|
|
1763
|
-
});
|
|
1764
|
-
await assertPass(schema, {
|
|
1765
|
-
tags: ['foo', 'bar'],
|
|
1766
|
-
});
|
|
1767
|
-
await assertFail(schema, {
|
|
1768
|
-
tags: 'foo',
|
|
1769
|
-
});
|
|
1770
|
-
});
|
|
1771
|
-
|
|
1772
|
-
it('should allow a mixed type array field', async () => {
|
|
1773
|
-
const schema = getValidationSchema({
|
|
1774
|
-
categories: {
|
|
1775
|
-
type: 'Array',
|
|
1776
|
-
},
|
|
1777
|
-
});
|
|
1778
|
-
await assertPass(schema, { categories: ['foo'] });
|
|
1779
|
-
await assertPass(schema, { categories: [] });
|
|
1780
|
-
await assertFail(schema, { categories: 'foo' });
|
|
1781
|
-
});
|
|
1782
|
-
});
|
|
1783
|
-
|
|
1784
|
-
describe('nested fields', () => {
|
|
1785
|
-
it('should validate nested field', async () => {
|
|
1786
|
-
const schema = getValidationSchema({
|
|
1787
|
-
counts: {
|
|
1788
|
-
view: 'Number',
|
|
1789
|
-
},
|
|
1790
|
-
});
|
|
1791
|
-
await assertPass(schema, { counts: { view: 1 } });
|
|
1792
|
-
await assertFail(schema, { counts: { view: 'bad number' } });
|
|
1793
|
-
});
|
|
1794
|
-
|
|
1795
|
-
it('should not validate mixed type', async () => {
|
|
1796
|
-
const schema = getValidationSchema({
|
|
1797
|
-
counts: 'Mixed',
|
|
1798
|
-
});
|
|
1799
|
-
await assertPass(schema, { counts: { foo: 'bar' } });
|
|
1800
|
-
await assertPass(schema, { counts: { name: 'foo' } });
|
|
1801
|
-
});
|
|
1802
|
-
|
|
1803
|
-
it('should not validate explicit mixed type', async () => {
|
|
1804
|
-
const schema = getValidationSchema({
|
|
1805
|
-
counts: {
|
|
1806
|
-
type: 'Mixed',
|
|
1807
|
-
},
|
|
1808
|
-
});
|
|
1809
|
-
await assertPass(schema, { counts: { foo: 'bar' } });
|
|
1810
|
-
await assertPass(schema, { counts: { name: 'foo' } });
|
|
1811
|
-
});
|
|
1812
|
-
|
|
1813
|
-
it('should validate mixed with nested type object', async () => {
|
|
1814
|
-
const schema = getValidationSchema({
|
|
1815
|
-
type: {
|
|
1816
|
-
type: 'String',
|
|
1817
|
-
required: true,
|
|
1818
|
-
},
|
|
1819
|
-
});
|
|
1820
|
-
await assertPass(schema, {
|
|
1821
|
-
type: 'foo',
|
|
1822
|
-
});
|
|
1823
|
-
await assertFail(schema, {
|
|
1824
|
-
type: {
|
|
1825
|
-
type: 'foo',
|
|
1826
|
-
},
|
|
1827
|
-
});
|
|
1828
|
-
await assertFail(schema, {});
|
|
1829
|
-
});
|
|
1830
|
-
});
|
|
1831
|
-
|
|
1832
|
-
describe('appendSchema', () => {
|
|
1833
|
-
it('should append plain objects as schemas', async () => {
|
|
1834
|
-
const schema = getValidationSchema(
|
|
1835
|
-
{
|
|
1836
|
-
type: {
|
|
1837
|
-
type: 'String',
|
|
1838
|
-
required: true,
|
|
1839
|
-
},
|
|
1840
|
-
},
|
|
1841
|
-
{
|
|
1842
|
-
appendSchema: {
|
|
1843
|
-
count: yd.number().required(),
|
|
1844
|
-
},
|
|
1845
|
-
}
|
|
1846
|
-
);
|
|
1847
|
-
await assertFail(schema, {
|
|
1848
|
-
type: 'foo',
|
|
1849
|
-
});
|
|
1850
|
-
await assertPass(schema, {
|
|
1851
|
-
type: 'foo',
|
|
1852
|
-
count: 10,
|
|
1853
|
-
});
|
|
1854
|
-
});
|
|
1855
|
-
|
|
1856
|
-
it('should merge schemas', async () => {
|
|
1857
|
-
const schema = getValidationSchema(
|
|
1858
|
-
{
|
|
1859
|
-
type: {
|
|
1860
|
-
type: 'String',
|
|
1861
|
-
required: true,
|
|
1862
|
-
},
|
|
1863
|
-
count: {
|
|
1864
|
-
type: 'Number',
|
|
1865
|
-
required: true,
|
|
1866
|
-
},
|
|
1867
|
-
},
|
|
1868
|
-
{
|
|
1869
|
-
appendSchema: yd.object({
|
|
1870
|
-
count: yd.number(),
|
|
1871
|
-
}),
|
|
1872
|
-
}
|
|
1873
|
-
);
|
|
1874
|
-
await assertPass(schema, {
|
|
1875
|
-
type: 'foo',
|
|
1876
|
-
});
|
|
1877
|
-
await assertPass(schema, {
|
|
1878
|
-
type: 'foo',
|
|
1879
|
-
count: 10,
|
|
1880
|
-
});
|
|
1881
|
-
});
|
|
1882
|
-
});
|
|
1883
|
-
});
|
|
1884
|
-
|
|
1885
|
-
describe('getNamedValidator', () => {
|
|
1886
|
-
it('should get an email validator', async () => {
|
|
1887
|
-
const emailValidator = getNamedValidator('email');
|
|
1888
|
-
await expect(emailValidator('foo@bar.com')).resolves.not.toThrow();
|
|
1889
|
-
await expect(emailValidator('bad@email')).rejects.toThrow();
|
|
1890
|
-
});
|
|
1891
|
-
});
|
|
1892
|
-
|
|
1893
|
-
describe('addValidators', () => {
|
|
1894
|
-
it('should be able to add a custom schema validator', async () => {
|
|
1895
|
-
addValidators({
|
|
1896
|
-
dog: yd.allow('Golden Retriever', 'Australian Shepherd'),
|
|
1897
|
-
});
|
|
1898
|
-
const User = createTestModel({
|
|
1899
|
-
dog: {
|
|
1900
|
-
type: 'String',
|
|
1901
|
-
validate: 'dog',
|
|
1902
|
-
},
|
|
1903
|
-
});
|
|
1904
|
-
|
|
1905
|
-
await expect(
|
|
1906
|
-
User.create({
|
|
1907
|
-
dog: 'Australian Shepherd',
|
|
1908
|
-
})
|
|
1909
|
-
).resolves.not.toThrow();
|
|
1910
|
-
|
|
1911
|
-
await expect(
|
|
1912
|
-
User.create({
|
|
1913
|
-
dog: 'Husky',
|
|
1914
|
-
})
|
|
1915
|
-
).rejects.toThrow();
|
|
1916
|
-
|
|
1917
|
-
const schema = User.getCreateValidation();
|
|
1918
|
-
await assertPass(schema, {
|
|
1919
|
-
dog: 'Australian Shepherd',
|
|
1920
|
-
});
|
|
1921
|
-
await assertFail(schema, {
|
|
1922
|
-
dog: 'Husky',
|
|
1923
|
-
});
|
|
1924
|
-
});
|
|
1925
|
-
});
|