// Load modules var Lab = require('lab'); var Code = require('code'); var Joi = require('../lib'); var Helper = require('./helper'); // Declare internals var internals = {}; // Test shortcuts var lab = exports.lab = Lab.script(); var describe = lab.describe; var it = lab.it; var expect = Code.expect; describe('date', function () { it('fails on boolean', function (done) { var schema = Joi.date(); Helper.validate(schema, [ [true, false], [false, false] ], done); }); it('matches specific date', function (done) { var now = Date.now(); Joi.date().valid(new Date(now)).validate(new Date(now), function (err, value) { expect(err).to.not.exist(); done(); }); }); it('errors on invalid input and convert disabled', function (done) { Joi.date().options({ convert: false }).validate('1-1-2013 UTC', function (err, value) { expect(err).to.exist(); expect(err.message).to.equal('"value" must be a number of milliseconds or valid date string'); done(); }); }); it('validates date', function (done) { Joi.date().validate(new Date(), function (err, value) { expect(err).to.not.exist(); done(); }); }); it('validates millisecond date as a string', function (done) { var now = new Date(); var mili = now.getTime(); Joi.date().validate(mili.toString(), function (err, value) { expect(err).to.not.exist(); expect(value).to.deep.equal(now); done(); }); }); describe('#validate', function () { describe('min', function () { it('validates min', function (done) { Helper.validate(Joi.date().min('1-1-2000 UTC'), [ ['1-1-2001 UTC', true], ['1-1-2000 UTC', true], [0, false], ['0', false], ['-1', false], ['1-1-1999 UTC', false] ], done); }); it('accepts "now" as the min date', function (done) { var future = new Date(Date.now() + 1000000); Joi.date().min('now').validate(future, function (err, value) { expect(err).to.not.exist(); expect(value).to.deep.equal(future); done(); }); }); it('errors if .min("now") is used with a past date', function (done) { var past = new Date(Date.now() - 1000000); Joi.date().min('now').validate(past, function (err, value) { expect(err).to.exist(); done(); }); }); it('accepts references as min date', function (done) { var schema = Joi.object({ a: Joi.date(), b: Joi.date().min(Joi.ref('a')) }); var now = Date.now(); Helper.validate(schema, [ [{ a: now, b: now }, true], [{ a: now, b: now + 1e3 }, true], [{ a: now, b: now - 1e3 }, false] ], done); }); it('accepts context references as min date', function (done) { var schema = Joi.object({ b: Joi.date().min(Joi.ref('$a')) }); var now = Date.now(); Helper.validate(schema, [ [{ b: now }, true, { context: { a: now } }], [{ b: now + 1e3 }, true, { context: { a: now } }], [{ b: now - 1e3 }, false, { context: { a: now } }] ], done); }); it('errors if reference is not a date', function (done) { var schema = Joi.object({ a: Joi.string(), b: Joi.date().min(Joi.ref('a')) }); var now = Date.now(); Helper.validate(schema, [ [{ a: 'abc', b: now }, false, null, 'child "b" fails because ["b" references "a" which is not a date]'], [{ a: '123', b: now }, true], [{ a: (now + 1e3).toString(), b: now }, false, null, /^child "b" fails because \["b" must be larger than or equal to/] ], done); }); it('errors if context reference is not a date', function (done) { var schema = Joi.object({ b: Joi.date().min(Joi.ref('$a')) }); var now = Date.now(); Helper.validate(schema, [ [{ b: now }, false, { context: { a: 'abc' } }, 'child "b" fails because ["b" references "a" which is not a date]'], [{ b: now }, false, { context: { a: (now + 1e3).toString() } }, /^child "b" fails because \["b" must be larger than or equal to/] ], done); }); }); describe('max', function () { it('validates max', function (done) { Helper.validate(Joi.date().max('1-1-1970 UTC'), [ ['1-1-1971 UTC', false], ['1-1-1970 UTC', true], [0, true], [1, false], ['0', true], ['-1', true], ['1-1-2014 UTC', false] ], done); }); it('accepts "now" as the max date', function (done) { var past = new Date(Date.now() - 1000000); Joi.date().max('now').validate(past, function (err, value) { expect(err).to.not.exist(); expect(value).to.deep.equal(past); done(); }); }); it('errors if .max("now") is used with a future date', function (done) { var future = new Date(Date.now() + 1000000); Joi.date().max('now').validate(future, function (err, value) { expect(err).to.exist(); done(); }); }); it('accepts references as max date', function (done) { var schema = Joi.object({ a: Joi.date(), b: Joi.date().max(Joi.ref('a')) }); var now = Date.now(); Helper.validate(schema, [ [{ a: now, b: now }, true], [{ a: now, b: now + 1e3 }, false], [{ a: now, b: now - 1e3 }, true] ], done); }); it('accepts references as max date', function (done) { var schema = Joi.object({ b: Joi.date().max(Joi.ref('$a')) }); var now = Date.now(); Helper.validate(schema, [ [{ b: now }, true, { context: { a: now } }], [{ b: now + 1e3 }, false, { context: { a: now } }], [{ b: now - 1e3 }, true, { context: { a: now } }] ], done); }); it('errors if reference is not a date', function (done) { var schema = Joi.object({ a: Joi.string(), b: Joi.date().max(Joi.ref('a')) }); var now = Date.now(); Helper.validate(schema, [ [{ a: 'abc', b: new Date() }, false, null, 'child "b" fails because ["b" references "a" which is not a date]'], [{ a: '100000000000000', b: now }, true], [{ a: (now - 1e3).toString(), b: now }, false, null, /^child "b" fails because \["b" must be less than or equal to/] ], done); }); it('errors if context reference is not a date', function (done) { var schema = Joi.object({ b: Joi.date().max(Joi.ref('$a')) }); var now = Date.now(); Helper.validate(schema, [ [{ b: now }, false, { context: { a: 'abc' } }, 'child "b" fails because ["b" references "a" which is not a date]'], [{ b: now }, true, { context: { a: '100000000000000' } }], [{ b: now }, false, { context: { a: (now - 1e3).toString() } }, /^child "b" fails because \["b" must be less than or equal to/] ], done); }); }); it('validates only valid dates', function (done) { Helper.validate(Joi.date(), [ ['1-1-2013 UTC', true], ['not a valid date', false], [new Date('not a valid date'), false] ], done); }); describe('#iso', function () { it('validates isoDate', function (done) { Helper.validate(Joi.date().iso(), [ ['2013-06-07T14:21:46.295Z', true], ['2013-06-07T14:21:46.295Z0', false], ['2013-06-07T14:21:46.295+07:00', true], ['2013-06-07T14:21:46.295+07:000', false], ['2013-06-07T14:21:46.295-07:00', true], ['2013-06-07T14:21:46Z', true], ['2013-06-07T14:21:46Z0', false], ['2013-06-07T14:21:46+07:00', true], ['2013-06-07T14:21:46-07:00', true], ['2013-06-07T14:21Z', true], ['2013-06-07T14:21+07:00', true], ['2013-06-07T14:21+07:000', false], ['2013-06-07T14:21-07:00', true], ['2013-06-07T14:21Z+7:00', false], ['2013-06-07', true], ['2013-06-07T', false], ['2013-06-07T14:21', true], ['1-1-2013', false] ], done); }); it('validates isoDate with a friendly error message', function (done) { var schema = { item: Joi.date().iso() }; Joi.compile(schema).validate({ item: 'something' }, function (err, value) { expect(err.message).to.contain('must be a valid ISO 8601 date'); done(); }); }); it('validates isoDate after clone', function (done) { var schema = { item: Joi.date().iso().clone() }; Joi.compile(schema).validate({ item: '2013-06-07T14:21:46.295Z' }, function (err, value) { expect(err).to.not.exist(); done(); }); }); }); describe('#format', function () { it('validates custom format', function (done) { Helper.validate(Joi.date().format('DD#YYYY$MM'), [ ['07#2013$06', true], ['2013-06-07', false] ], done); }); it('validates several custom formats', function (done) { Helper.validate(Joi.date().format(['DD#YYYY$MM', 'YY|DD|MM']), [ ['13|07|06', true], ['2013-06-07', false] ], done); }); it('fails with bad formats', function (done) { expect(function () { Joi.date().format(true); }).to.throw('Invalid format.'); expect(function () { Joi.date().format(['YYYYMMDD', true]); }).to.throw('Invalid format.'); done(); }); }); }); });