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('advanced', function(t) {
24 var validate = validator(cosmic.schema)
26 t.ok(validate(cosmic.valid), 'should be valid')
27 t.notOk(validate(cosmic.invalid), 'should be invalid')
31 tape('greedy/false', function(t) {
32 var validate = validator({
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')
58 tape('greedy/true', function(t) {
59 var validate = validator({
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')
90 tape('additional props', function(t) {
91 var validate = validator({
93 additionalProperties: false
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.strictEqual(validate.errors[0].type, 'object', 'error object should contain the type')
105 tape('array', function(t) {
106 var validate = validator({
114 t.notOk(validate({}), 'wrong type')
115 t.notOk(validate(), 'is required')
116 t.ok(validate(['test']))
120 tape('nested array', function(t) {
121 var validate = validator({
134 t.notOk(validate({}), 'is required')
135 t.ok(validate({list:['test']}))
136 t.notOk(validate({list:[1]}))
140 tape('enum', function(t) {
141 var validate = validator({
152 t.notOk(validate({}), 'is required')
153 t.ok(validate({foo:42}))
154 t.notOk(validate({foo:43}))
158 tape('minimum/maximum', function(t) {
159 var validate = validator({
170 t.notOk(validate({foo:-42}))
171 t.ok(validate({foo:0}))
172 t.notOk(validate({foo:42}))
176 tape('exclusiveMinimum/exclusiveMaximum', function(t) {
177 var validate = validator({
184 exclusiveMinimum: true,
185 exclusiveMaximum: true
190 t.notOk(validate({foo:10}))
191 t.ok(validate({foo:11}))
192 t.notOk(validate({foo:20}))
193 t.ok(validate({foo:19}))
197 tape('custom format', function(t) {
198 var validate = validator({
206 }, {formats: {as:/^a+$/}})
208 t.notOk(validate({foo:''}), 'not as')
209 t.notOk(validate({foo:'b'}), 'not as')
210 t.notOk(validate({foo:'aaab'}), 'not as')
211 t.ok(validate({foo:'a'}), 'as')
212 t.ok(validate({foo:'aaaaaa'}), 'as')
216 tape('custom format function', function(t) {
217 var validate = validator({
225 }, {formats: {as:function(s) { return /^a+$/.test(s) } }})
227 t.notOk(validate({foo:''}), 'not as')
228 t.notOk(validate({foo:'b'}), 'not as')
229 t.notOk(validate({foo:'aaab'}), 'not as')
230 t.ok(validate({foo:'a'}), 'as')
231 t.ok(validate({foo:'aaaaaa'}), 'as')
235 tape('do not mutate schema', function(t) {
245 var copy = JSON.parse(JSON.stringify(sch))
249 t.same(sch, copy, 'did not mutate')
253 tape('#toJSON()', function(t) {
258 hello: {type:'string', required:true}
262 var validate = validator(schema)
264 t.deepEqual(validate.toJSON(), schema, 'should return original schema')
268 tape('external schemas', function(t) {
269 var ext = {type: 'string'}
275 var validate = validator(schema, {schemas: {ext:ext}})
277 t.ok(validate('hello string'), 'is a string')
278 t.notOk(validate(42), 'not a string')
282 tape('external schema URIs', function(t) {
283 var ext = {type: 'string'}
286 $ref: 'http://example.com/schemas/schemaURIs'
289 var opts = {schemas:{}};
290 opts.schemas['http://example.com/schemas/schemaURIs'] = ext;
291 var validate = validator(schema, opts)
293 t.ok(validate('hello string'), 'is a string')
294 t.notOk(validate(42), 'not a string')
298 tape('top-level external schema', function(t) {
305 enum: ["male", "female", "other"]
311 "name": { $ref: "definitions.json#/string" },
312 "sex": { $ref: "definitions.json#/sex" }
314 required: ["name", "sex"]
317 var validate = validator(schema, {
319 "definitions.json": defs
322 t.ok(validate({name:"alice", sex:"female"}), 'is an object')
323 t.notOk(validate({name:"alice", sex: "bob"}), 'recognizes external schema')
324 t.notOk(validate({name:2, sex: "female"}), 'recognizes external schema')
328 tape('nested required array decl', function(t) {
349 var validate = validator(schema)
351 t.ok(validate({x: {}}), 'should be valid')
352 t.notOk(validate({}), 'should not be valid')
353 t.strictEqual(validate.errors[0].field, 'data.x', 'should output the missing field')
357 tape('verbose mode', function(t) {
369 var validate = validator(schema, {verbose: true})
371 t.ok(validate({hello: 'string'}), 'should be valid')
372 t.notOk(validate({hello: 100}), 'should not be valid')
373 t.strictEqual(validate.errors[0].value, 100, 'error object should contain the invalid value')
374 t.strictEqual(validate.errors[0].type, 'string', 'error object should contain the type')
378 tape('additional props in verbose mode', function(t) {
382 additionalProperties: false,
390 additionalProperties: false,
400 var validate = validator(schema, {verbose: true})
402 validate({'hello world': {bar: 'string'}});
404 t.strictEqual(validate.errors[0].value, 'data["hello world"].bar', 'should output the path to the additional prop in the error')
408 tape('Date.now() is an integer', function(t) {
409 var schema = {type: 'integer'}
410 var validate = validator(schema)
412 t.ok(validate(Date.now()), 'is integer')
416 tape('field shows item index in arrays', function(t) {
432 var validate = validator(schema)
445 t.strictEqual(validate.errors[0].field, 'data.1.1.foo', 'should output the field with specific index of failing item in the error')