joi 8.4.2 → 9.0.0-0

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/test/date.js ADDED
@@ -0,0 +1,441 @@
1
+ 'use strict';
2
+
3
+ // Load modules
4
+
5
+ const Lab = require('lab');
6
+ const Code = require('code');
7
+ const Joi = require('../lib');
8
+ const Helper = require('./helper');
9
+
10
+
11
+ // Declare internals
12
+
13
+ const internals = {};
14
+
15
+
16
+ // Test shortcuts
17
+
18
+ const lab = exports.lab = Lab.script();
19
+ const describe = lab.describe;
20
+ const it = lab.it;
21
+ const expect = Code.expect;
22
+
23
+
24
+ describe('date', () => {
25
+
26
+ it('fails on boolean', (done) => {
27
+
28
+ const schema = Joi.date();
29
+ Helper.validate(schema, [
30
+ [true, false],
31
+ [false, false]
32
+ ], done);
33
+ });
34
+
35
+ it('fails on non-finite numbers', (done) => {
36
+
37
+ const schema = Joi.date();
38
+ Helper.validate(schema, [
39
+ [Infinity, false, null, /number of milliseconds or valid date string/],
40
+ [-Infinity, false, null, /number of milliseconds or valid date string/],
41
+ [NaN, false, null, /number of milliseconds or valid date string/]
42
+ ], done);
43
+ });
44
+
45
+ it('matches specific date', (done) => {
46
+
47
+ const now = Date.now();
48
+ Joi.date().valid(new Date(now)).validate(new Date(now), (err, value) => {
49
+
50
+ expect(err).to.not.exist();
51
+ done();
52
+ });
53
+ });
54
+
55
+ it('errors on invalid input and convert disabled', (done) => {
56
+
57
+ Joi.date().options({ convert: false }).validate('1-1-2013 UTC', (err, value) => {
58
+
59
+ expect(err).to.exist();
60
+ expect(err.message).to.equal('"value" must be a number of milliseconds or valid date string');
61
+ done();
62
+ });
63
+ });
64
+
65
+ it('validates date', (done) => {
66
+
67
+ Joi.date().validate(new Date(), (err, value) => {
68
+
69
+ expect(err).to.not.exist();
70
+ done();
71
+ });
72
+ });
73
+
74
+ it('validates millisecond date as a string', (done) => {
75
+
76
+ const now = new Date();
77
+ const mili = now.getTime();
78
+
79
+ Joi.date().validate(mili.toString(), (err, value) => {
80
+
81
+ expect(err).to.not.exist();
82
+ expect(value).to.deep.equal(now);
83
+ done();
84
+ });
85
+ });
86
+
87
+ describe('validate()', () => {
88
+
89
+ describe('min', () => {
90
+
91
+ it('validates min', (done) => {
92
+
93
+ Helper.validate(Joi.date().min('1-1-2000 UTC'), [
94
+ ['1-1-2001 UTC', true],
95
+ ['1-1-2000 UTC', true],
96
+ [0, false],
97
+ ['0', false],
98
+ ['-1', false],
99
+ ['1-1-1999 UTC', false]
100
+ ], done);
101
+ });
102
+
103
+ it('accepts "now" as the min date', (done) => {
104
+
105
+ const future = new Date(Date.now() + 1000000);
106
+
107
+ Joi.date().min('now').validate(future, (err, value) => {
108
+
109
+ expect(err).to.not.exist();
110
+ expect(value).to.deep.equal(future);
111
+ done();
112
+ });
113
+ });
114
+
115
+ it('errors if .min("now") is used with a past date', (done) => {
116
+
117
+ const past = new Date(Date.now() - 1000000);
118
+
119
+ Joi.date().min('now').validate(past, (err, value) => {
120
+
121
+ expect(err).to.exist();
122
+ done();
123
+ });
124
+ });
125
+
126
+ it('accepts references as min date', (done) => {
127
+
128
+ const schema = Joi.object({ a: Joi.date(), b: Joi.date().min(Joi.ref('a')) });
129
+ const now = Date.now();
130
+
131
+ Helper.validate(schema, [
132
+ [{ a: now, b: now }, true],
133
+ [{ a: now, b: now + 1e3 }, true],
134
+ [{ a: now, b: now - 1e3 }, false]
135
+ ], done);
136
+ });
137
+
138
+ it('accepts context references as min date', (done) => {
139
+
140
+ const schema = Joi.object({ b: Joi.date().min(Joi.ref('$a')) });
141
+ const now = Date.now();
142
+
143
+ Helper.validate(schema, [
144
+ [{ b: now }, true, { context: { a: now } }],
145
+ [{ b: now + 1e3 }, true, { context: { a: now } }],
146
+ [{ b: now - 1e3 }, false, { context: { a: now } }]
147
+ ], done);
148
+ });
149
+
150
+ it('errors if reference is not a date', (done) => {
151
+
152
+ const schema = Joi.object({ a: Joi.string(), b: Joi.date().min(Joi.ref('a')) });
153
+ const now = Date.now();
154
+
155
+ Helper.validate(schema, [
156
+ [{ a: 'abc', b: now }, false, null, 'child "b" fails because ["b" references "a" which is not a date]'],
157
+ [{ a: '123', b: now }, true],
158
+ [{ a: (now + 1e3).toString(), b: now }, false, null, /^child "b" fails because \["b" must be larger than or equal to/]
159
+ ], done);
160
+ });
161
+
162
+ it('errors if context reference is not a date', (done) => {
163
+
164
+ const schema = Joi.object({ b: Joi.date().min(Joi.ref('$a')) });
165
+ const now = Date.now();
166
+
167
+ Helper.validate(schema, [
168
+ [{ b: now }, false, { context: { a: 'abc' } }, 'child "b" fails because ["b" references "a" which is not a date]'],
169
+ [{ b: now }, false, { context: { a: (now + 1e3).toString() } }, /^child "b" fails because \["b" must be larger than or equal to/]
170
+ ], done);
171
+ });
172
+ });
173
+
174
+ describe('max', () => {
175
+
176
+ it('validates max', (done) => {
177
+
178
+ Helper.validate(Joi.date().max('1-1-1970 UTC'), [
179
+ ['1-1-1971 UTC', false],
180
+ ['1-1-1970 UTC', true],
181
+ [0, true],
182
+ [1, false],
183
+ ['0', true],
184
+ ['-1', true],
185
+ ['1-1-2014 UTC', false]
186
+ ], done);
187
+ });
188
+
189
+ it('accepts "now" as the max date', (done) => {
190
+
191
+ const past = new Date(Date.now() - 1000000);
192
+
193
+ Joi.date().max('now').validate(past, (err, value) => {
194
+
195
+ expect(err).to.not.exist();
196
+ expect(value).to.deep.equal(past);
197
+ done();
198
+ });
199
+ });
200
+
201
+ it('errors if .max("now") is used with a future date', (done) => {
202
+
203
+ const future = new Date(Date.now() + 1000000);
204
+
205
+ Joi.date().max('now').validate(future, (err, value) => {
206
+
207
+ expect(err).to.exist();
208
+ done();
209
+ });
210
+ });
211
+
212
+ it('accepts references as max date', (done) => {
213
+
214
+ const schema = Joi.object({ a: Joi.date(), b: Joi.date().max(Joi.ref('a')) });
215
+ const now = Date.now();
216
+
217
+ Helper.validate(schema, [
218
+ [{ a: now, b: now }, true],
219
+ [{ a: now, b: now + 1e3 }, false],
220
+ [{ a: now, b: now - 1e3 }, true]
221
+ ], done);
222
+ });
223
+
224
+ it('accepts references as max date', (done) => {
225
+
226
+ const schema = Joi.object({ b: Joi.date().max(Joi.ref('$a')) });
227
+ const now = Date.now();
228
+
229
+ Helper.validate(schema, [
230
+ [{ b: now }, true, { context: { a: now } }],
231
+ [{ b: now + 1e3 }, false, { context: { a: now } }],
232
+ [{ b: now - 1e3 }, true, { context: { a: now } }]
233
+ ], done);
234
+ });
235
+
236
+ it('errors if reference is not a date', (done) => {
237
+
238
+ const schema = Joi.object({ a: Joi.string(), b: Joi.date().max(Joi.ref('a')) });
239
+ const now = Date.now();
240
+
241
+ Helper.validate(schema, [
242
+ [{ a: 'abc', b: new Date() }, false, null, 'child "b" fails because ["b" references "a" which is not a date]'],
243
+ [{ a: '100000000000000', b: now }, true],
244
+ [{ a: (now - 1e3).toString(), b: now }, false, null, /^child "b" fails because \["b" must be less than or equal to/]
245
+ ], done);
246
+ });
247
+
248
+ it('errors if context reference is not a date', (done) => {
249
+
250
+ const schema = Joi.object({ b: Joi.date().max(Joi.ref('$a')) });
251
+ const now = Date.now();
252
+
253
+ Helper.validate(schema, [
254
+ [{ b: now }, false, { context: { a: 'abc' } }, 'child "b" fails because ["b" references "a" which is not a date]'],
255
+ [{ b: now }, true, { context: { a: '100000000000000' } }],
256
+ [{ b: now }, false, { context: { a: (now - 1e3).toString() } }, /^child "b" fails because \["b" must be less than or equal to/]
257
+ ], done);
258
+ });
259
+ });
260
+
261
+ it('validates only valid dates', (done) => {
262
+
263
+ Helper.validate(Joi.date(), [
264
+ ['1-1-2013 UTC', true],
265
+ [new Date().getTime(), true],
266
+ [new Date().getTime().toFixed(4), true],
267
+ ['not a valid date', false],
268
+ [new Date('not a valid date'), false]
269
+ ], done);
270
+ });
271
+
272
+ describe('iso()', () => {
273
+
274
+ it('validates isoDate', (done) => {
275
+
276
+ Helper.validate(Joi.date().iso(), [
277
+ ['2013-06-07T14:21:46.295Z', true],
278
+ ['2013-06-07T14:21:46.295Z0', false],
279
+ ['2013-06-07T14:21:46.295+07:00', true],
280
+ ['2013-06-07T14:21:46.295+07:000', false],
281
+ ['2013-06-07T14:21:46.295-07:00', true],
282
+ ['2013-06-07T14:21:46Z', true],
283
+ ['2013-06-07T14:21:46Z0', false],
284
+ ['2013-06-07T14:21:46+07:00', true],
285
+ ['2013-06-07T14:21:46-07:00', true],
286
+ ['2013-06-07T14:21Z', true],
287
+ ['2013-06-07T14:21+07:00', true],
288
+ ['2013-06-07T14:21+07:000', false],
289
+ ['2013-06-07T14:21-07:00', true],
290
+ ['2013-06-07T14:21Z+7:00', false],
291
+ ['2013-06-07', true],
292
+ ['2013-06-07T', false],
293
+ ['2013-06-07T14:21', true],
294
+ ['1-1-2013', false]
295
+ ], done);
296
+ });
297
+
298
+ it('validates isoDate with a friendly error message', (done) => {
299
+
300
+ const schema = { item: Joi.date().iso() };
301
+ Joi.compile(schema).validate({ item: 'something' }, (err, value) => {
302
+
303
+ expect(err.message).to.contain('must be a valid ISO 8601 date');
304
+ done();
305
+ });
306
+ });
307
+
308
+ it('validates isoDate after clone', (done) => {
309
+
310
+ const schema = { item: Joi.date().iso().clone() };
311
+ Joi.compile(schema).validate({ item: '2013-06-07T14:21:46.295Z' }, (err, value) => {
312
+
313
+ expect(err).to.not.exist();
314
+ done();
315
+ });
316
+ });
317
+ });
318
+
319
+ describe('timestamp()', () => {
320
+
321
+ it('validates javascript timestamp', (done) => {
322
+
323
+ const now = new Date();
324
+ const milliseconds = now.getTime();
325
+
326
+ Joi.date().timestamp().validate(milliseconds, (err, value) => {
327
+
328
+ expect(err).to.not.exist();
329
+ expect(value).to.deep.equal(now);
330
+ });
331
+ Joi.date().timestamp('javascript').validate(milliseconds, (err, value) => {
332
+
333
+ expect(err).to.not.exist();
334
+ expect(value).to.deep.equal(now);
335
+ });
336
+ Joi.date().timestamp('unix').timestamp('javascript').validate(milliseconds, (err, value) => {
337
+
338
+ expect(err).to.not.exist();
339
+ expect(value).to.deep.equal(now);
340
+ });
341
+ done();
342
+ });
343
+
344
+ it('validates unix timestamp', (done) => {
345
+
346
+ const now = new Date();
347
+ const seconds = now.getTime() / 1000;
348
+
349
+ Joi.date().timestamp('unix').validate(seconds, (err, value) => {
350
+
351
+ expect(err).to.not.exist();
352
+ expect(value).to.deep.equal(now);
353
+ });
354
+ Joi.date().timestamp().timestamp('unix').validate(seconds, (err, value) => {
355
+
356
+ expect(err).to.not.exist();
357
+ expect(value).to.deep.equal(now);
358
+ });
359
+ Joi.date().timestamp('javascript').timestamp('unix').validate(seconds, (err, value) => {
360
+
361
+ expect(err).to.not.exist();
362
+ expect(value).to.deep.equal(now);
363
+ });
364
+ done();
365
+ });
366
+
367
+ it('validates timestamps with decimals', (done) => {
368
+
369
+ Helper.validate(Joi.date().timestamp(), [
370
+ [new Date().getTime().toFixed(4), true]
371
+ ]);
372
+ Helper.validate(Joi.date().timestamp('javascript'), [
373
+ [new Date().getTime().toFixed(4), true]
374
+ ]);
375
+ Helper.validate(Joi.date().timestamp('unix'), [
376
+ [(new Date().getTime() / 1000).toFixed(4), true]
377
+ ]);
378
+ done();
379
+ });
380
+
381
+ it('validates only valid timestamps and returns a friendly error message', (done) => {
382
+
383
+ Helper.validate(Joi.date().timestamp(), [
384
+ [new Date().getTime(), true],
385
+ [new Date().getTime().toFixed(4), true],
386
+ ['1.452126061677e+12', true],
387
+ [1.452126061677e+12, true],
388
+ [1E3, true],
389
+ ['1E3', true],
390
+ [',', false, null, /must be a valid timestamp/],
391
+ ['123A,0xA', false, null, /must be a valid timestamp/],
392
+ ['1-1-2013 UTC', false, null, /must be a valid timestamp/],
393
+ ['not a valid timestamp', false, null, /must be a valid timestamp/],
394
+ [new Date('not a valid date'), false, null, /must be a valid timestamp/]
395
+ ], done);
396
+ });
397
+
398
+ it('fails with not allowed type', (done) => {
399
+
400
+ expect(() => {
401
+
402
+ Joi.date().timestamp('not allowed');
403
+ }).to.throw(Error, /"type" must be one of/);
404
+ done();
405
+ });
406
+ });
407
+
408
+ describe('format()', () => {
409
+
410
+ it('validates custom format', (done) => {
411
+
412
+ Helper.validate(Joi.date().format('DD#YYYY$MM'), [
413
+ ['07#2013$06', true],
414
+ ['2013-06-07', false]
415
+ ], done);
416
+ });
417
+
418
+ it('validates several custom formats', (done) => {
419
+
420
+ Helper.validate(Joi.date().format(['DD#YYYY$MM', 'YY|DD|MM']), [
421
+ ['13|07|06', true],
422
+ ['2013-06-07', false]
423
+ ], done);
424
+ });
425
+
426
+ it('fails with bad formats', (done) => {
427
+
428
+ expect(() => {
429
+
430
+ Joi.date().format(true);
431
+ }).to.throw('Invalid format.');
432
+
433
+ expect(() => {
434
+
435
+ Joi.date().format(['YYYYMMDD', true]);
436
+ }).to.throw('Invalid format.');
437
+ done();
438
+ });
439
+ });
440
+ });
441
+ });