1 var tape = require('tape')
2 var cosmic = require('./fixtures/cosmic')
3 var validator = require('../')
4 var validatorRequire = require('../require')
6 tape('simple', function(t) {
11 hello: {type:'string', required:true}
15 var validate = validator(schema)
17 t.ok(validate({hello: 'world'}), 'should be valid')
18 t.notOk(validate(), 'should be invalid')
19 t.notOk(validate({}), 'should be invalid')
23 tape('data is undefined', function (t) {
24 var validate = validator({type: 'string'})
26 t.notOk(validate(null))
27 t.notOk(validate(undefined))
31 tape('advanced', function(t) {
32 var validate = validator(cosmic.schema)
34 t.ok(validate(cosmic.valid), 'should be valid')
35 t.notOk(validate(cosmic.invalid), 'should be invalid')
39 tape('greedy/false', function(t) {
40 var validate = validator({
49 t.notOk(validate({}), 'should be invalid')
50 t.strictEqual(validate.errors.length, 2);
51 t.strictEqual(validate.errors[0].field, 'data.x')
52 t.strictEqual(validate.errors[0].message, 'is required')
53 t.strictEqual(validate.errors[1].field, 'data.y')
54 t.strictEqual(validate.errors[1].message, 'is required')
55 t.notOk(validate({x: 'string'}), 'should be invalid')
56 t.strictEqual(validate.errors.length, 1);
57 t.strictEqual(validate.errors[0].field, 'data.y')
58 t.strictEqual(validate.errors[0].message, 'is required')
59 t.notOk(validate({x: 'string', y: 'value'}), 'should be invalid')
60 t.strictEqual(validate.errors.length, 1);
61 t.strictEqual(validate.errors[0].field, 'data.x')
62 t.strictEqual(validate.errors[0].message, 'is the wrong type')
66 tape('greedy/true', function(t) {
67 var validate = validator({
78 t.notOk(validate({}), 'should be invalid')
79 t.strictEqual(validate.errors.length, 2);
80 t.strictEqual(validate.errors[0].field, 'data.x')
81 t.strictEqual(validate.errors[0].message, 'is required')
82 t.strictEqual(validate.errors[1].field, 'data.y')
83 t.strictEqual(validate.errors[1].message, 'is required')
84 t.notOk(validate({x: 'string'}), 'should be invalid')
85 t.strictEqual(validate.errors.length, 2);
86 t.strictEqual(validate.errors[0].field, 'data.y')
87 t.strictEqual(validate.errors[0].message, 'is required')
88 t.strictEqual(validate.errors[1].field, 'data.x')
89 t.strictEqual(validate.errors[1].message, 'is the wrong type')
90 t.notOk(validate({x: 'string', y: 'value'}), 'should be invalid')
91 t.strictEqual(validate.errors.length, 1);
92 t.strictEqual(validate.errors[0].field, 'data.x')
93 t.strictEqual(validate.errors[0].message, 'is the wrong type')
94 t.ok(validate({x: 1, y: 'value'}), 'should be invalid')
98 tape('additional props', function(t) {
99 var validate = validator({
101 additionalProperties: false
107 t.notOk(validate({foo:'bar'}))
108 t.ok(validate.errors[0].value === 'data.foo', 'should output the property not allowed in verbose mode')
109 t.strictEqual(validate.errors[0].type, 'object', 'error object should contain the type')
113 tape('array', function(t) {
114 var validate = validator({
122 t.notOk(validate({}), 'wrong type')
123 t.notOk(validate(), 'is required')
124 t.ok(validate(['test']))
128 tape('nested array', function(t) {
129 var validate = validator({
142 t.notOk(validate({}), 'is required')
143 t.ok(validate({list:['test']}))
144 t.notOk(validate({list:[1]}))
148 tape('enum', function(t) {
149 var validate = validator({
160 t.notOk(validate({}), 'is required')
161 t.ok(validate({foo:42}))
162 t.notOk(validate({foo:43}))
166 tape('minimum/maximum', function(t) {
167 var validate = validator({
178 t.notOk(validate({foo:-42}))
179 t.ok(validate({foo:0}))
180 t.notOk(validate({foo:42}))
184 tape('exclusiveMinimum/exclusiveMaximum', function(t) {
185 var validate = validator({
192 exclusiveMinimum: true,
193 exclusiveMaximum: true
198 t.notOk(validate({foo:10}))
199 t.ok(validate({foo:11}))
200 t.notOk(validate({foo:20}))
201 t.ok(validate({foo:19}))
205 tape('minimum/maximum number type', function(t) {
206 var validate = validator({
207 type: ['integer', 'null'],
212 t.notOk(validate(-1))
217 t.notOk(validate(101))
221 tape('custom format', function(t) {
222 var validate = validator({
230 }, {formats: {as:/^a+$/}})
232 t.notOk(validate({foo:''}), 'not as')
233 t.notOk(validate({foo:'b'}), 'not as')
234 t.notOk(validate({foo:'aaab'}), 'not as')
235 t.ok(validate({foo:'a'}), 'as')
236 t.ok(validate({foo:'aaaaaa'}), 'as')
240 tape('custom format function', function(t) {
241 var validate = validator({
249 }, {formats: {as:function(s) { return /^a+$/.test(s) } }})
251 t.notOk(validate({foo:''}), 'not as')
252 t.notOk(validate({foo:'b'}), 'not as')
253 t.notOk(validate({foo:'aaab'}), 'not as')
254 t.ok(validate({foo:'a'}), 'as')
255 t.ok(validate({foo:'aaaaaa'}), 'as')
259 tape('do not mutate schema', function(t) {
269 var copy = JSON.parse(JSON.stringify(sch))
273 t.same(sch, copy, 'did not mutate')
277 tape('#toJSON()', function(t) {
282 hello: {type:'string', required:true}
286 var validate = validator(schema)
288 t.deepEqual(validate.toJSON(), schema, 'should return original schema')
292 tape('external schemas', function(t) {
293 var ext = {type: 'string'}
299 var validate = validator(schema, {schemas: {ext:ext}})
301 t.ok(validate('hello string'), 'is a string')
302 t.notOk(validate(42), 'not a string')
306 tape('external schema URIs', function(t) {
307 var ext = {type: 'string'}
310 $ref: 'http://example.com/schemas/schemaURIs'
313 var opts = {schemas:{}};
314 opts.schemas['http://example.com/schemas/schemaURIs'] = ext;
315 var validate = validator(schema, opts)
317 t.ok(validate('hello string'), 'is a string')
318 t.notOk(validate(42), 'not a string')
322 tape('top-level external schema', function(t) {
329 enum: ["male", "female", "other"]
335 "name": { $ref: "definitions.json#/string" },
336 "sex": { $ref: "definitions.json#/sex" }
338 required: ["name", "sex"]
341 var validate = validator(schema, {
343 "definitions.json": defs
346 t.ok(validate({name:"alice", sex:"female"}), 'is an object')
347 t.notOk(validate({name:"alice", sex: "bob"}), 'recognizes external schema')
348 t.notOk(validate({name:2, sex: "female"}), 'recognizes external schema')
352 tape('nested required array decl', function(t) {
373 var validate = validator(schema)
375 t.ok(validate({x: {}}), 'should be valid')
376 t.notOk(validate({}), 'should not be valid')
377 t.strictEqual(validate.errors[0].field, 'data.x', 'should output the missing field')
381 tape('verbose mode', function(t) {
393 var validate = validator(schema, {verbose: true})
395 t.ok(validate({hello: 'string'}), 'should be valid')
396 t.notOk(validate({hello: 100}), 'should not be valid')
397 t.strictEqual(validate.errors[0].value, 100, 'error object should contain the invalid value')
398 t.strictEqual(validate.errors[0].type, 'string', 'error object should contain the type')
402 tape('additional props in verbose mode', function(t) {
406 additionalProperties: false,
414 additionalProperties: false,
424 var validate = validator(schema, {verbose: true})
426 validate({'hello world': {bar: 'string'}});
428 t.strictEqual(validate.errors[0].value, 'data["hello world"].bar', 'should output the path to the additional prop in the error')
432 tape('Date.now() is an integer', function(t) {
433 var schema = {type: 'integer'}
434 var validate = validator(schema)
436 t.ok(validate(Date.now()), 'is integer')
440 tape('field shows item index in arrays', function(t) {
456 var validate = validator(schema)
469 t.strictEqual(validate.errors[0].field, 'data.1.1.foo', 'should output the field with specific index of failing item in the error')