Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
81155 views
1
var tape = require('tape')
2
var cosmic = require('./fixtures/cosmic')
3
var validator = require('../')
4
var validatorRequire = require('../require')
5
6
tape('simple', function(t) {
7
var schema = {
8
required: true,
9
type: 'object',
10
properties: {
11
hello: {type:'string', required:true}
12
}
13
}
14
15
var validate = validator(schema)
16
17
t.ok(validate({hello: 'world'}), 'should be valid')
18
t.notOk(validate(), 'should be invalid')
19
t.notOk(validate({}), 'should be invalid')
20
t.end()
21
})
22
23
tape('advanced', function(t) {
24
var validate = validator(cosmic.schema)
25
26
t.ok(validate(cosmic.valid), 'should be valid')
27
t.notOk(validate(cosmic.invalid), 'should be invalid')
28
t.end()
29
})
30
31
tape('greedy/false', function(t) {
32
var validate = validator({
33
type: 'object',
34
properties: {
35
x: {
36
type: 'number'
37
}
38
},
39
required: ['x', 'y']
40
});
41
t.notOk(validate({}), 'should be invalid')
42
t.strictEqual(validate.errors.length, 2);
43
t.strictEqual(validate.errors[0].field, 'data.x')
44
t.strictEqual(validate.errors[0].message, 'is required')
45
t.strictEqual(validate.errors[1].field, 'data.y')
46
t.strictEqual(validate.errors[1].message, 'is required')
47
t.notOk(validate({x: 'string'}), 'should be invalid')
48
t.strictEqual(validate.errors.length, 1);
49
t.strictEqual(validate.errors[0].field, 'data.y')
50
t.strictEqual(validate.errors[0].message, 'is required')
51
t.notOk(validate({x: 'string', y: 'value'}), 'should be invalid')
52
t.strictEqual(validate.errors.length, 1);
53
t.strictEqual(validate.errors[0].field, 'data.x')
54
t.strictEqual(validate.errors[0].message, 'is the wrong type')
55
t.end();
56
});
57
58
tape('greedy/true', function(t) {
59
var validate = validator({
60
type: 'object',
61
properties: {
62
x: {
63
type: 'number'
64
}
65
},
66
required: ['x', 'y']
67
}, {
68
greedy: true
69
});
70
t.notOk(validate({}), 'should be invalid')
71
t.strictEqual(validate.errors.length, 2);
72
t.strictEqual(validate.errors[0].field, 'data.x')
73
t.strictEqual(validate.errors[0].message, 'is required')
74
t.strictEqual(validate.errors[1].field, 'data.y')
75
t.strictEqual(validate.errors[1].message, 'is required')
76
t.notOk(validate({x: 'string'}), 'should be invalid')
77
t.strictEqual(validate.errors.length, 2);
78
t.strictEqual(validate.errors[0].field, 'data.y')
79
t.strictEqual(validate.errors[0].message, 'is required')
80
t.strictEqual(validate.errors[1].field, 'data.x')
81
t.strictEqual(validate.errors[1].message, 'is the wrong type')
82
t.notOk(validate({x: 'string', y: 'value'}), 'should be invalid')
83
t.strictEqual(validate.errors.length, 1);
84
t.strictEqual(validate.errors[0].field, 'data.x')
85
t.strictEqual(validate.errors[0].message, 'is the wrong type')
86
t.ok(validate({x: 1, y: 'value'}), 'should be invalid')
87
t.end();
88
});
89
90
tape('additional props', function(t) {
91
var validate = validator({
92
type: 'object',
93
additionalProperties: false
94
}, {
95
verbose: true
96
})
97
98
t.ok(validate({}))
99
t.notOk(validate({foo:'bar'}))
100
t.ok(validate.errors[0].value === 'data.foo', 'should output the property not allowed in verbose mode')
101
t.end()
102
})
103
104
tape('array', function(t) {
105
var validate = validator({
106
type: 'array',
107
required: true,
108
items: {
109
type: 'string'
110
}
111
})
112
113
t.notOk(validate({}), 'wrong type')
114
t.notOk(validate(), 'is required')
115
t.ok(validate(['test']))
116
t.end()
117
})
118
119
tape('nested array', function(t) {
120
var validate = validator({
121
type: 'object',
122
properties: {
123
list: {
124
type: 'array',
125
required: true,
126
items: {
127
type: 'string'
128
}
129
}
130
}
131
})
132
133
t.notOk(validate({}), 'is required')
134
t.ok(validate({list:['test']}))
135
t.notOk(validate({list:[1]}))
136
t.end()
137
})
138
139
tape('enum', function(t) {
140
var validate = validator({
141
type: 'object',
142
properties: {
143
foo: {
144
type: 'number',
145
required: true,
146
enum: [42]
147
}
148
}
149
})
150
151
t.notOk(validate({}), 'is required')
152
t.ok(validate({foo:42}))
153
t.notOk(validate({foo:43}))
154
t.end()
155
})
156
157
tape('minimum/maximum', function(t) {
158
var validate = validator({
159
type: 'object',
160
properties: {
161
foo: {
162
type: 'number',
163
minimum: 0,
164
maximum: 0
165
}
166
}
167
})
168
169
t.notOk(validate({foo:-42}))
170
t.ok(validate({foo:0}))
171
t.notOk(validate({foo:42}))
172
t.end()
173
})
174
175
tape('exclusiveMinimum/exclusiveMaximum', function(t) {
176
var validate = validator({
177
type: 'object',
178
properties: {
179
foo: {
180
type: 'number',
181
minimum: 10,
182
maximum: 20,
183
exclusiveMinimum: true,
184
exclusiveMaximum: true
185
}
186
}
187
})
188
189
t.notOk(validate({foo:10}))
190
t.ok(validate({foo:11}))
191
t.notOk(validate({foo:20}))
192
t.ok(validate({foo:19}))
193
t.end()
194
})
195
196
tape('custom format', function(t) {
197
var validate = validator({
198
type: 'object',
199
properties: {
200
foo: {
201
type: 'string',
202
format: 'as'
203
}
204
}
205
}, {formats: {as:/^a+$/}})
206
207
t.notOk(validate({foo:''}), 'not as')
208
t.notOk(validate({foo:'b'}), 'not as')
209
t.notOk(validate({foo:'aaab'}), 'not as')
210
t.ok(validate({foo:'a'}), 'as')
211
t.ok(validate({foo:'aaaaaa'}), 'as')
212
t.end()
213
})
214
215
tape('custom format function', function(t) {
216
var validate = validator({
217
type: 'object',
218
properties: {
219
foo: {
220
type: 'string',
221
format: 'as'
222
}
223
}
224
}, {formats: {as:function(s) { return /^a+$/.test(s) } }})
225
226
t.notOk(validate({foo:''}), 'not as')
227
t.notOk(validate({foo:'b'}), 'not as')
228
t.notOk(validate({foo:'aaab'}), 'not as')
229
t.ok(validate({foo:'a'}), 'as')
230
t.ok(validate({foo:'aaaaaa'}), 'as')
231
t.end()
232
})
233
234
tape('do not mutate schema', function(t) {
235
var sch = {
236
items: [
237
{}
238
],
239
additionalItems: {
240
type: 'integer'
241
}
242
}
243
244
var copy = JSON.parse(JSON.stringify(sch))
245
246
validator(sch)
247
248
t.same(sch, copy, 'did not mutate')
249
t.end()
250
})
251
252
tape('#toJSON()', function(t) {
253
var schema = {
254
required: true,
255
type: 'object',
256
properties: {
257
hello: {type:'string', required:true}
258
}
259
}
260
261
var validate = validator(schema)
262
263
t.deepEqual(validate.toJSON(), schema, 'should return original schema')
264
t.end()
265
})
266
267
tape('external schemas', function(t) {
268
var ext = {type: 'string'}
269
var schema = {
270
required: true,
271
$ref: '#ext'
272
}
273
274
var validate = validator(schema, {schemas: {ext:ext}})
275
276
t.ok(validate('hello string'), 'is a string')
277
t.notOk(validate(42), 'not a string')
278
t.end()
279
})
280
281
tape('top-level external schema', function(t) {
282
var defs = {
283
"string": {
284
type: "string"
285
},
286
"sex": {
287
type: "string",
288
enum: ["male", "female", "other"]
289
}
290
}
291
var schema = {
292
type: "object",
293
properties: {
294
"name": { $ref: "definitions.json#/string" },
295
"sex": { $ref: "definitions.json#/sex" }
296
},
297
required: ["name", "sex"]
298
}
299
300
var validate = validator(schema, {
301
schemas: {
302
"definitions.json": defs
303
}
304
})
305
t.ok(validate({name:"alice", sex:"female"}), 'is an object')
306
t.notOk(validate({name:"alice", sex: "bob"}), 'recognizes external schema')
307
t.notOk(validate({name:2, sex: "female"}), 'recognizes external schema')
308
t.end()
309
})
310
311
tape('nested required array decl', function(t) {
312
var schema = {
313
properties: {
314
x: {
315
type: 'object',
316
properties: {
317
y: {
318
type: 'object',
319
properties: {
320
z: {
321
type: 'string'
322
}
323
},
324
required: ['z']
325
}
326
}
327
}
328
},
329
required: ['x']
330
}
331
332
var validate = validator(schema)
333
334
t.ok(validate({x: {}}), 'should be valid')
335
t.notOk(validate({}), 'should not be valid')
336
t.strictEqual(validate.errors[0].field, 'data.x', 'should output the missing field')
337
t.end()
338
})
339
340
tape('verbose mode', function(t) {
341
var schema = {
342
required: true,
343
type: 'object',
344
properties: {
345
hello: {
346
required: true,
347
type: 'string'
348
}
349
}
350
};
351
352
var validate = validator(schema, {verbose: true})
353
354
t.ok(validate({hello: 'string'}), 'should be valid')
355
t.notOk(validate({hello: 100}), 'should not be valid')
356
t.strictEqual(validate.errors[0].value, 100, 'error object should contain the invalid value')
357
t.end()
358
})
359
360
tape('additional props in verbose mode', function(t) {
361
var schema = {
362
type: 'object',
363
required: true,
364
additionalProperties: false,
365
properties: {
366
foo: {
367
type: 'string'
368
},
369
'hello world': {
370
type: 'object',
371
required: true,
372
additionalProperties: false,
373
properties: {
374
foo: {
375
type: 'string'
376
}
377
}
378
}
379
}
380
};
381
382
var validate = validator(schema, {verbose: true})
383
384
validate({'hello world': {bar: 'string'}});
385
386
t.strictEqual(validate.errors[0].value, 'data["hello world"].bar', 'should output the path to the additional prop in the error')
387
t.end()
388
})
389
390
tape('Date.now() is an integer', function(t) {
391
var schema = {type: 'integer'}
392
var validate = validator(schema)
393
394
t.ok(validate(Date.now()), 'is integer')
395
t.end()
396
})
397
398
tape('field shows item index in arrays', function(t) {
399
var schema = {
400
type: 'array',
401
items: {
402
type: 'array',
403
items: {
404
properties: {
405
foo: {
406
type: 'string',
407
required: true
408
}
409
}
410
}
411
}
412
}
413
414
var validate = validator(schema)
415
416
validate([
417
[
418
{ foo: 'test' },
419
{ foo: 'test' }
420
],
421
[
422
{ foo: 'test' },
423
{ baz: 'test' }
424
]
425
])
426
427
t.strictEqual(validate.errors[0].field, 'data.1.1.foo', 'should output the field with specific index of failing item in the error')
428
t.end()
429
})
430
431