1 | import test from 'ava'
|
2 | import Chance from '../chance.js'
|
3 | import _ from 'lodash'
|
4 |
|
5 | const chance = new Chance()
|
6 |
|
7 |
|
8 | const CHILD_AGE_MIN = 0
|
9 | const CHILD_AGE_MAX = 12
|
10 | const TEEN_AGE_MIN = 13
|
11 | const TEEN_AGE_MAX = 19
|
12 | const ADULT_AGE_MIN = 18
|
13 | const ADULT_AGE_MAX = 65
|
14 | const SENIOR_AGE_MIN = 65
|
15 | const SENIOR_AGE_MAX = 100
|
16 | const AGE_MIN = 0
|
17 | const AGE_MAX = 100
|
18 |
|
19 | const now = Object.freeze(new Date())
|
20 | const currentYear = now.getFullYear()
|
21 |
|
22 |
|
23 | const ymd = dt => ({y: dt.getFullYear(), m: dt.getMonth(), d: dt.getDate()})
|
24 | const today = ymd(now)
|
25 | const age = dt => {
|
26 |
|
27 |
|
28 | const dob = ymd(dt)
|
29 | const completed = (today.m > dob.m || (today.m === dob.m && today.d >= dob.d))
|
30 | return (today.y - dob.y) - (completed ? 0 : 1)
|
31 | }
|
32 |
|
33 |
|
34 | test('age() returns a random age within expected bounds', t => {
|
35 | _.times(1000, () => {
|
36 | let age = chance.age()
|
37 | t.true(_.isNumber(age))
|
38 | t.true(age >= ADULT_AGE_MIN)
|
39 | t.true(age <= ADULT_AGE_MAX)
|
40 | })
|
41 | })
|
42 |
|
43 | test('age() returns a random age within expected bounds for all', t => {
|
44 | _.times(1000, () => {
|
45 | let age = chance.age({ type: 'all' })
|
46 | t.true(_.isNumber(age))
|
47 | t.true(age >= AGE_MIN)
|
48 | t.true(age <= AGE_MAX)
|
49 | })
|
50 | })
|
51 |
|
52 | test('age() returns a proper age for a child', t => {
|
53 | _.times(1000, () => {
|
54 | let age = chance.age({ type: 'child' })
|
55 | t.true(_.isNumber(age))
|
56 | t.true(age >= CHILD_AGE_MIN)
|
57 | t.true(age <= CHILD_AGE_MAX)
|
58 | })
|
59 | })
|
60 |
|
61 | test('age() returns a proper age for a teen', t => {
|
62 | _.times(1000, () => {
|
63 | let age = chance.age({ type: 'teen' })
|
64 | t.true(_.isNumber(age))
|
65 | t.true(age >= TEEN_AGE_MIN)
|
66 | t.true(age <= TEEN_AGE_MAX)
|
67 | })
|
68 | })
|
69 |
|
70 | test('age() returns a proper age for an adult', t => {
|
71 | _.times(1000, () => {
|
72 | let age = chance.age({ type: 'adult' })
|
73 | t.true(_.isNumber(age))
|
74 | t.true(age >= ADULT_AGE_MIN)
|
75 | t.true(age <= ADULT_AGE_MAX)
|
76 | })
|
77 | })
|
78 |
|
79 | test('age() returns a proper age for a senior', t => {
|
80 | _.times(1000, () => {
|
81 | let age = chance.age({ type: 'senior' })
|
82 | t.true(_.isNumber(age))
|
83 | t.true(age >= SENIOR_AGE_MIN)
|
84 | t.true(age <= SENIOR_AGE_MAX)
|
85 | })
|
86 | })
|
87 |
|
88 |
|
89 | test('birthday() works as expected', t => {
|
90 | _.times(1000, () => {
|
91 | let birthday = chance.birthday()
|
92 | t.true(_.isDate(birthday))
|
93 | let year = birthday.getFullYear()
|
94 | let curYear = new Date().getFullYear()
|
95 | t.true(year > (curYear - AGE_MAX))
|
96 | t.true(year < curYear)
|
97 | })
|
98 | })
|
99 |
|
100 | test('birthday() can have a string returned', t => {
|
101 | _.times(1000, () => {
|
102 | let birthday = chance.birthday({ string: true })
|
103 | t.true(_.isString(birthday))
|
104 | t.false(_.isDate(birthday))
|
105 | t.true(/^[0-9][0-9]?\/[0-9][0-9]?\/[0-9]{4}/m.test(birthday))
|
106 | })
|
107 | })
|
108 |
|
109 | test('birthday() can have a year specified', t => {
|
110 | _.times(1000, () => {
|
111 | t.is(chance.birthday({ year: 1983 }).getFullYear(), 1983)
|
112 | })
|
113 | })
|
114 |
|
115 | test('birthday() can have an age range specified for an adult', t => {
|
116 | _.times(1000, () => {
|
117 | let birthday = chance.birthday({ type: 'adult' })
|
118 | let min = new Date().setFullYear(currentYear - ADULT_AGE_MAX - 1)
|
119 | let max = new Date().setFullYear(currentYear - ADULT_AGE_MIN)
|
120 | t.true(birthday.getTime() >= min)
|
121 | t.true(birthday.getTime() <= max)
|
122 | })
|
123 | })
|
124 |
|
125 | test('birthday() can have an age range specified for a teen', t => {
|
126 | _.times(1000, () => {
|
127 | let birthday = chance.birthday({ type: 'teen' })
|
128 | let min = new Date().setFullYear(currentYear - TEEN_AGE_MAX - 1)
|
129 | let max = new Date().setFullYear(currentYear - TEEN_AGE_MIN)
|
130 | t.true(birthday.getTime() >= min)
|
131 | t.true(birthday.getTime() <= max)
|
132 | })
|
133 | })
|
134 |
|
135 | test('birthday() can have an age range specified for a child', t => {
|
136 | _.times(1000, () => {
|
137 | let birthday = chance.birthday({ type: 'child' })
|
138 | let min = new Date().setFullYear(currentYear - CHILD_AGE_MAX - 1)
|
139 | let max = new Date().setFullYear(currentYear - CHILD_AGE_MIN)
|
140 | t.true(birthday.getTime() >= min)
|
141 | t.true(birthday.getTime() <= max)
|
142 | })
|
143 | })
|
144 |
|
145 | test('birthday() can have an age range specified for a senior', t => {
|
146 | _.times(1000, () => {
|
147 | let birthday = chance.birthday({ type: 'senior' })
|
148 | let min = new Date().setFullYear(currentYear - SENIOR_AGE_MAX - 1)
|
149 | let max = new Date().setFullYear(currentYear - SENIOR_AGE_MIN)
|
150 | t.true(birthday.getTime() >= min)
|
151 | t.true(birthday.getTime() <= max)
|
152 | })
|
153 | })
|
154 |
|
155 | test('birthday() can have an age range specified by minAge only', t => {
|
156 | for(let minAge=0; minAge < 100; minAge++)
|
157 | _.times(10, () => {
|
158 | let birthday = chance.birthday({ minAge })
|
159 | const calculated = age(birthday)
|
160 | t.true(calculated >= minAge, JSON.stringify({birthday, calculated}))
|
161 | })
|
162 | })
|
163 |
|
164 | test('birthday() can have an age range specified by maxAge only', t => {
|
165 | for(let maxAge=0; maxAge < 100; maxAge++)
|
166 | _.times(10, () => {
|
167 | let birthday = chance.birthday({ maxAge })
|
168 | const calculated = age(birthday)
|
169 | t.true(calculated <= maxAge, JSON.stringify({birthday, calculated}))
|
170 | })
|
171 | })
|
172 |
|
173 | test('birthday() can have an age range specified by minAge and maxAge', t => {
|
174 | for(let minAge=0; minAge < 100; minAge++)
|
175 | for(let maxAge=minAge; maxAge < 100; maxAge++)
|
176 | _.times(10, () => {
|
177 | let birthday = chance.birthday({ minAge, maxAge })
|
178 | const calculated = age(birthday)
|
179 | t.true(calculated >= minAge, JSON.stringify({birthday, calculated}))
|
180 | t.true(calculated <= maxAge, JSON.stringify({birthday, calculated}))
|
181 | })
|
182 | })
|
183 |
|
184 | test('birthday() throws an error if minAge < 0', t => {
|
185 | const fn = () => chance.birthday({ minAge: -1 })
|
186 | t.throws(fn, 'Chance: MinAge cannot be less than zero.')
|
187 | })
|
188 |
|
189 | test('birthday() throws an error if minAge > maxAge', t => {
|
190 | const fn = () => chance.birthday({ minAge: 30, maxAge: 10 })
|
191 | t.throws(fn, 'Chance: MinAge cannot be greater than MaxAge.')
|
192 | })
|
193 |
|
194 |
|
195 | test('cnpj() returns a random cnpj', t => {
|
196 | _.times(1000, () => {
|
197 | let hidn = chance.HIDN()
|
198 | t.true(_.isString(hidn))
|
199 | })
|
200 | })
|
201 |
|
202 |
|
203 | test('company() returns a random company', t => {
|
204 | _.times(1000, () => {
|
205 | let company = chance.company()
|
206 | t.true(_.isString(company))
|
207 | t.true(company.length > 4)
|
208 | })
|
209 | })
|
210 |
|
211 |
|
212 | test('cpf() returns a random valid taxpayer number for Brazil citizens (CPF)', t => {
|
213 | _.times(1000, () => {
|
214 | let cpf = chance.cpf()
|
215 | t.true(_.isString(cpf))
|
216 | t.true(/^\d{3}.\d{3}.\d{3}-\d{2}$/m.test(cpf))
|
217 | t.is(cpf.length, 14)
|
218 | })
|
219 | })
|
220 |
|
221 |
|
222 | test('first() returns a random first name', t => {
|
223 | _.times(1000, () => {
|
224 | let first = chance.first()
|
225 | t.true(_.isString(first))
|
226 | t.true(first.length >= 2)
|
227 | t.true(first.length <= 20)
|
228 | t.is(first.split(' ').length, 1)
|
229 | })
|
230 | })
|
231 |
|
232 |
|
233 | test('gender() returns a random gender', t => {
|
234 | _.times(1000, () => t.true(/(Male|Female)/.test(chance.gender())))
|
235 | })
|
236 |
|
237 | test('gender() can take extra genders', t => {
|
238 | _.times(1000, () => {
|
239 | let gender = chance.gender({ extraGenders: ['Unknown', 'Transgender'] })
|
240 | t.true(/(Male|Female|Unknown|Transgender)/.test(gender))
|
241 | })
|
242 | })
|
243 |
|
244 |
|
245 | test('HIDN() returns a random HIDN', t => {
|
246 | _.times(1000, () => {
|
247 | let hidn = chance.HIDN()
|
248 | t.true(_.isString(hidn))
|
249 | t.true(/^\d{6}[A-Z]{2}$/m.test(hidn))
|
250 | t.is(hidn.length, 8)
|
251 | })
|
252 | })
|
253 |
|
254 |
|
255 | test('israelId() returns a valid Isreal id', t => {
|
256 | let id = chance.israelId()
|
257 | t.true(_.isString(id))
|
258 | t.is(id.length, 9)
|
259 | let acc = 0
|
260 | for (let i = 0; i < 8; i++) {
|
261 | let thisDigit = id[i] * ( i / 2 === parseInt(i/2, 10) ? 1 : 2)
|
262 | thisDigit = chance.pad(thisDigit, 2)
|
263 | thisDigit = parseInt(thisDigit[0], 10) + parseInt(thisDigit[1], 10)
|
264 | acc += thisDigit
|
265 | }
|
266 | let lastDigit = (10 - parseInt(acc.toString().slice(-1), 10).toString().slice(-1)).toString().slice(-1)
|
267 | t.is(id[8], lastDigit)
|
268 | })
|
269 |
|
270 |
|
271 | test('last() returns a random last name', t => {
|
272 | _.times(1000, () => {
|
273 | let last = chance.last()
|
274 | t.true(_.isString(last))
|
275 | t.true(last.length >= 2)
|
276 | t.true(last.length <= 20)
|
277 | t.true(last.split(' ').length <= 3)
|
278 | })
|
279 | })
|
280 |
|
281 |
|
282 | test('name() returns a random name', t => {
|
283 | _.times(1000, () => {
|
284 | let name = chance.name()
|
285 | t.true(_.isString(name))
|
286 | t.true(name.length >= 2)
|
287 | t.true(name.length <= 30)
|
288 | t.is(name.split(' ').length, 2)
|
289 | t.true(/[a-zA-Z]+\ [a-zA-Z]+/.test(name))
|
290 | })
|
291 | })
|
292 |
|
293 | test('name() can have the middle name specified', t => {
|
294 | _.times(1000, () => {
|
295 | let name = chance.name({ middle: true })
|
296 | t.true(_.isString(name))
|
297 | t.is(name.split(' ').length, 3)
|
298 | t.true(/[a-zA-Z]+\ [a-zA-Z]+\ [a-zA-Z]+/.test(name))
|
299 | })
|
300 | })
|
301 |
|
302 | test('name() can have the middle initial specified', t => {
|
303 | _.times(1000, () => {
|
304 | let name = chance.name({ middle_initial: true })
|
305 | t.true(_.isString(name))
|
306 | t.is(name.split(' ').length, 3)
|
307 | t.true(/[a-zA-Z]+\ [a-zA-Z]\.\ [a-zA-Z]+/.test(name))
|
308 | })
|
309 | })
|
310 |
|
311 | test('name() can have the prefix specified', t => {
|
312 | _.times(1000, () => {
|
313 | let name = chance.name({ prefix: true })
|
314 | t.true(_.isString(name))
|
315 | t.is(name.split(' ').length, 3)
|
316 | t.true(/[a-zA-Z]{2,4}\.? [a-zA-Z]+\ [a-zA-Z]+/.test(name))
|
317 | })
|
318 | })
|
319 |
|
320 | test('name() can have the suffix specified', t => {
|
321 | _.times(1000, () => {
|
322 | let name = chance.name({ suffix: true })
|
323 | t.true(_.isString(name))
|
324 | t.is(name.split(' ').length, 3)
|
325 | t.true(/[a-zA-Z]+\ [a-zA-Z]+\ [a-zA-Z\.]+/.test(name))
|
326 | })
|
327 | })
|
328 |
|
329 |
|
330 | test('name_prefix() returns a random prefix', t => {
|
331 | _.times(1000, () => {
|
332 | let prefix = chance.name_prefix()
|
333 | t.true(_.isString(prefix))
|
334 | t.true(prefix.length < 5)
|
335 | })
|
336 | })
|
337 |
|
338 | test('name_prefix() returns a correctly gendered prefix', t => {
|
339 | _.times(1000, () => {
|
340 | let prefix = chance.name_prefix({ gender: 'female' })
|
341 | t.not(prefix, 'Mr.')
|
342 | prefix = chance.name_prefix({ gender: 'male' })
|
343 | t.not(prefix, 'Mrs.')
|
344 | t.not(prefix, 'Miss')
|
345 | })
|
346 | })
|
347 |
|
348 | test('name_prefix() can return a full prefix', t => {
|
349 | _.times(1000, () => {
|
350 | let prefix = chance.name_prefix({ full: true })
|
351 | t.true(_.isString(prefix))
|
352 | t.true(prefix.length > 3)
|
353 | })
|
354 | })
|
355 |
|
356 |
|
357 | test('name_suffix() returns a random suffix', t => {
|
358 | _.times(1000, () => {
|
359 | let suffix = chance.name_suffix()
|
360 | t.true(_.isString(suffix))
|
361 | t.true(suffix.length < 7)
|
362 | })
|
363 | })
|
364 |
|
365 | test('name_suffix() can return a full suffix', t => {
|
366 | _.times(1000, () => {
|
367 | let suffix = chance.name_suffix({ full: true })
|
368 | t.true(_.isString(suffix))
|
369 | t.true(suffix.length > 5)
|
370 | })
|
371 | })
|
372 |
|
373 |
|
374 | test('nationality() returns a nationality that looks right', t => {
|
375 | _.times(1000, () => {
|
376 | let nationality = chance.nationality()
|
377 | t.true(_.isString(nationality))
|
378 | t.true(nationality.length > 3)
|
379 | t.true(nationality.length < 26)
|
380 | })
|
381 | })
|
382 |
|
383 |
|
384 | test('profession() returns a random profession', t => {
|
385 | _.times(1000, () => {
|
386 | let profession = chance.profession()
|
387 | t.true(_.isString(profession))
|
388 | t.true(profession.length > 3)
|
389 | })
|
390 | })
|
391 |
|
392 | test('profession() returns a ranked profession', t => {
|
393 | _.times(1000, () => {
|
394 | let profession = chance.profession({ rank: true })
|
395 | t.true(_.isString(profession))
|
396 | t.true(profession.split(' ').length > 1)
|
397 | t.true(/(Apprentice|Junior|Senior|Lead)/.test(profession.split(' ')[0]))
|
398 | })
|
399 | })
|
400 |
|
401 |
|
402 | test('ssn() returns a random social security number', t => {
|
403 | _.times(1000, () => {
|
404 | let ssn = chance.ssn()
|
405 | t.true(_.isString(ssn))
|
406 | t.true(/^\d{3}-\d{2}-\d{4}$/m.test(ssn))
|
407 | t.is(ssn.length, 11)
|
408 | })
|
409 | })
|
410 |
|
411 | test('ssn() can return just the last 4', t => {
|
412 | _.times(1000, () => {
|
413 | let ssn = chance.ssn({ ssnFour: true })
|
414 | t.true(_.isString(ssn))
|
415 | t.true(/^\d{4}$/m.test(ssn))
|
416 | t.is(ssn.length, 4)
|
417 | })
|
418 | })
|
419 |
|
420 |
|
421 | test('aadhar() returns a random aadhar number with whitespace as separator', t => {
|
422 | _.times(1000, () => {
|
423 | let aadhar = chance.aadhar()
|
424 | t.true(_.isString(aadhar))
|
425 | t.true(/^\d{4}\s\d{4}\s\d{4}$/m.test(aadhar))
|
426 | t.is(aadhar.length, 14)
|
427 | })
|
428 | })
|
429 |
|
430 |
|
431 | test('aadhar() returns a random aadhar number with no separator', t => {
|
432 | _.times(1000, () => {
|
433 | let aadhar = chance.aadhar({separatedByWhiteSpace : false})
|
434 | t.true(_.isString(aadhar))
|
435 | t.true(/^\d{12}$/m.test(aadhar))
|
436 | t.is(aadhar.length, 12)
|
437 | })
|
438 | })
|
439 |
|
440 |
|
441 | test('aadhar() can return just the last 4', t => {
|
442 | _.times(1000, () => {
|
443 | let aadhar = chance.aadhar({ onlyLastFour: true })
|
444 | t.true(_.isString(aadhar))
|
445 | t.true(/^\d{4}$/m.test(aadhar))
|
446 | t.is(aadhar.length, 4)
|
447 | })
|
448 | })
|
449 |
|
450 |
|
451 | test('suffix() returns a random suffix', t => {
|
452 | _.times(1000, () => {
|
453 | let suffix = chance.suffix()
|
454 | t.true(_.isString(suffix))
|
455 | t.true(suffix.length < 7)
|
456 | })
|
457 | })
|
458 |
|
459 | test('suffix() returns a full random suffix', t => {
|
460 | _.times(1000, () => {
|
461 | let suffix = chance.suffix({ full: true })
|
462 | t.true(_.isString(suffix))
|
463 | t.true(suffix.length > 5)
|
464 | })
|
465 | })
|
466 |
|
467 |
|
468 | test('mrz() should return a valid passport number', t => {
|
469 | let sample = "P<GBRFOLKS<<JOANNE<<<<<<<<<<<<<<<<<<<<<<<<<<2321126135GBR6902069F1601013<<<<<<<<<<<<<<02"
|
470 | let mrz = chance.mrz({
|
471 | first: 'Joanne',
|
472 | last: 'Folks',
|
473 | gender: 'F',
|
474 | dob: '690206',
|
475 | expiry: '160101',
|
476 | passportNumber: '232112613',
|
477 | })
|
478 | t.is(sample, mrz)
|
479 |
|
480 | sample = "P<GBRKELLY<<LIDA<<<<<<<<<<<<<<<<<<<<<<<<<<<<3071365913GBR6606068F2003131<<<<<<<<<<<<<<04"
|
481 | mrz = chance.mrz({
|
482 | first: 'Lida',
|
483 | last: 'Kelly',
|
484 | gender: 'F',
|
485 | dob: '660606',
|
486 | expiry: '200313',
|
487 | passportNumber: '307136591',
|
488 | })
|
489 | t.is(sample, mrz)
|
490 | })
|
491 |
|
492 | test('mrz() should return a valid random passport number when not given any inputs', t => {
|
493 | let mrz = chance.mrz()
|
494 | t.true(_.isString(mrz))
|
495 | t.is(mrz.substr(0, 5), 'P<GBR')
|
496 | t.is(mrz.length, 88)
|
497 | t.true(/^[A-Z0-9<]{9}[0-9]{1}[A-Z]{3}[0-9]{7}[A-Z]{1}[0-9]{7}[A-Z0-9<]{14}[0-9]{2}$/.test(mrz.substr(44)))
|
498 | })
|
499 |
|
500 | test('zodiac() return a random zodiac symbol', t => {
|
501 | _.times(1000, () => {
|
502 | const zodiacSymbols = ["Aries","Taurus","Gemini","Cancer","Leo","Virgo","Libra","Scorpio","Sagittarius","Capricorn","Aquarius","Pisces"];
|
503 | let symbol = chance.zodiac()
|
504 | t.true(_.isString(symbol))
|
505 | t.true(zodiacSymbols.includes(symbol))
|
506 | })
|
507 | })
|