diff --git a/src/date.ts b/src/date.ts index dcc2360091b..6c9b910065f 100644 --- a/src/date.ts +++ b/src/date.ts @@ -1,6 +1,32 @@ import type { Faker } from '.'; import type { DateEntryDefinition } from './definitions'; +/** + * Converts date passed as a string or Date to a Date object. If nothing passed, takes current date. + * + * @param date Date + */ +function toDate(date?: string | Date): Date { + if (date != null) { + return new Date(date instanceof Date ? date : Date.parse(date)); + } + + return new Date(); +} + +/** + * Converts date passed as a string or Date to milliseconds. If nothing passed, takes current date. + * + * @param date Date + */ +function toMilliseconds(date?: string | Date): number { + if (date != null) { + return date instanceof Date ? date.getTime() : Date.parse(date); + } + + return new Date().getTime(); +} + /** * Module to generate dates. */ @@ -28,12 +54,8 @@ export class _Date { * faker.date.past(10) // '2017-10-25T21:34:19.488Z' * faker.date.past(10, '2020-01-01T00:00:00.000Z') // '2017-08-18T02:59:12.350Z' */ - past(years?: number, refDate?: string): Date { - let date = new Date(); - if (typeof refDate !== 'undefined') { - date = new Date(Date.parse(refDate)); - } - + past(years?: number, refDate?: string | Date): Date { + const date = toDate(refDate); const range = { min: 1000, max: (years || 1) * 365 * 24 * 3600 * 1000, @@ -59,12 +81,8 @@ export class _Date { * faker.date.future(10) // '2030-11-23T09:38:28.710Z' * faker.date.future(10, '2020-01-01T00:00:00.000Z') // '2020-12-13T22:45:10.252Z' */ - future(years?: number, refDate?: string): Date { - let date = new Date(); - if (typeof refDate !== 'undefined') { - date = new Date(Date.parse(refDate)); - } - + future(years?: number, refDate?: string | Date): Date { + const date = toDate(refDate); const range = { min: 1000, max: (years || 1) * 365 * 24 * 3600 * 1000, @@ -86,13 +104,12 @@ export class _Date { * @example * faker.date.between('2020-01-01T00:00:00.000Z', '2030-01-01T00:00:00.000Z') // '2026-05-16T02:22:53.002Z' */ - between(from: string, to: string): Date { - const fromMilli = Date.parse(from); - const dateOffset = this.faker.datatype.number(Date.parse(to) - fromMilli); - - const newDate = new Date(fromMilli + dateOffset); + between(from: string | Date, to: string | Date): Date { + const fromMs = toMilliseconds(from); + const toMs = toMilliseconds(to); + const dateOffset = this.faker.datatype.number(toMs - fromMs); - return newDate; + return new Date(fromMs + dateOffset); } /** @@ -112,22 +129,18 @@ export class _Date { * faker.date.betweens('2020-01-01T00:00:00.000Z', '2030-01-01T00:00:00.000Z', 2) * // [ 2023-05-02T16:00:00.000Z, 2026-09-01T08:00:00.000Z ] */ - betweens(from: string, to: string, num?: number): Date[] { + betweens(from: string | Date, to: string | Date, num?: number): Date[] { if (typeof num === 'undefined') { num = 3; } - const newDates: Date[] = []; - let fromMilli = Date.parse(from); - const dateOffset = (Date.parse(to) - fromMilli) / (num + 1); - let lastDate: string | Date = from; + + const dates: Date[] = []; + for (let i = 0; i < num; i++) { - // TODO @Shinigami92 2022-01-11: It may be a bug that `lastDate` is passed to parse if it's a `Date` not a `string` - // @ts-expect-error - fromMilli = Date.parse(lastDate); - lastDate = new Date(fromMilli + dateOffset); - newDates.push(lastDate); + dates.push(this.between(from, to)); } - return newDates; + + return dates.sort((a, b) => a.getTime() - b.getTime()); } /** @@ -143,12 +156,8 @@ export class _Date { * faker.date.recent(10) // '2022-01-29T06:12:12.829Z' * faker.date.recent(10, '2020-01-01T00:00:00.000Z') // '2019-12-27T18:11:19.117Z' */ - recent(days?: number, refDate?: string): Date { - let date = new Date(); - if (typeof refDate !== 'undefined') { - date = new Date(Date.parse(refDate)); - } - + recent(days?: number, refDate?: string | Date): Date { + const date = toDate(refDate); const range = { min: 1000, max: (days || 1) * 24 * 3600 * 1000, @@ -174,12 +183,8 @@ export class _Date { * faker.date.soon(10) // '2022-02-11T05:14:39.138Z' * faker.date.soon(10, '2020-01-01T00:00:00.000Z') // '2020-01-01T02:40:44.990Z' */ - soon(days?: number, refDate?: string): Date { - let date = new Date(); - if (typeof refDate !== 'undefined') { - date = new Date(Date.parse(refDate)); - } - + soon(days?: number, refDate?: string | Date): Date { + const date = toDate(refDate); const range = { min: 1000, max: (days || 1) * 24 * 3600 * 1000, diff --git a/src/fake.ts b/src/fake.ts index 726bf89695e..4261ebebbc2 100644 --- a/src/fake.ts +++ b/src/fake.ts @@ -116,6 +116,10 @@ export class Fake { // replace the found tag with the returned fake value res = str.replace('{{' + token + '}}', result); + if (res === '') { + return ''; + } + // return the response recursively until we are done finding all tags return this.fake(res); } diff --git a/src/finance.ts b/src/finance.ts index b71e63b2e5c..37f491fe3a1 100644 --- a/src/finance.ts +++ b/src/finance.ts @@ -249,7 +249,7 @@ export class Finance { /** * Generates a random credit card number. * - * @param provider The (lowercase) name of the provider or the format used to generate one. + * @param provider The name of the provider (case insensitive) or the format used to generate one. * * @example * faker.finance.creditCardNumber() // '4427163488668' @@ -259,8 +259,9 @@ export class Finance { creditCardNumber(provider = ''): string { let format: string; const localeFormat = this.faker.definitions.finance.credit_card; - if (provider in localeFormat) { - format = this.faker.random.arrayElement(localeFormat[provider]); + const normalizedProvider = provider.toLowerCase(); + if (normalizedProvider in localeFormat) { + format = this.faker.random.arrayElement(localeFormat[normalizedProvider]); } else if (provider.match(/#/)) { // The user chose an optional scheme format = provider; diff --git a/src/helpers.ts b/src/helpers.ts index ddf19ed905e..2ee9faf529f 100644 --- a/src/helpers.ts +++ b/src/helpers.ts @@ -594,8 +594,6 @@ export class Helpers { email: this.faker.internet.email(userName), dob: this.faker.date.past( 50, - // TODO @Shinigami92 2022-01-14: We may need to convert this to a string - // @ts-expect-error new Date('Sat Sep 20 1992 21:35:02 GMT+0200 (CEST)') ), phone: this.faker.phone.phoneNumber(), diff --git a/src/vehicle.ts b/src/vehicle.ts index 58fb63a14f2..e2678bee4d4 100644 --- a/src/vehicle.ts +++ b/src/vehicle.ts @@ -1,15 +1,10 @@ import type { Faker } from '.'; -import type { Fake } from './fake'; - -let fake: Fake['fake']; /** * Module to generate vehicle related entries. */ export class Vehicle { constructor(private readonly faker: Faker) { - fake = faker.fake; - // Bind `this` so namespaced is working correctly for (const name of Object.getOwnPropertyNames(Vehicle.prototype)) { if (name === 'constructor' || typeof this[name] !== 'function') { @@ -26,7 +21,7 @@ export class Vehicle { * faker.vehicle.vehicle() // 'BMW Explorer' */ vehicle(): string { - return fake('{{vehicle.manufacturer}} {{vehicle.model}}'); + return `${this.manufacturer()} ${this.model()}`; } /** @@ -98,7 +93,7 @@ export class Vehicle { * faker.vehicle.color() // 'red' */ color(): string { - return fake('{{commerce.color}}'); + return this.faker.commerce.color(); } /** diff --git a/test/date.spec.ts b/test/date.spec.ts index a6af2cb5d00..1d6f8832892 100644 --- a/test/date.spec.ts +++ b/test/date.spec.ts @@ -5,50 +5,30 @@ const seededRuns = [ { seed: 42, expectations: { - past: [ - new Date('2020-10-08T00:10:58.041Z'), - new Date('2020-10-08T00:10:57.330Z'), - new Date('2017-05-26T15:26:24.637Z'), - new Date('2017-05-26T15:26:23.926Z'), - ], - future: [ - new Date('2021-07-08T10:07:33.381Z'), - new Date('2021-07-08T10:07:32.670Z'), - new Date('2024-11-19T18:52:06.785Z'), - new Date('2024-11-19T18:52:06.074Z'), - ], - between: [ - new Date('2021-03-15T19:30:57.091Z'), - new Date('2021-07-29T19:19:12.731Z'), - ], + past: { + noArgs: new Date('2020-10-08T00:10:58.041Z'), + ten: new Date('2017-05-26T15:26:24.637Z'), + }, + future: { + noArgs: new Date('2021-07-08T10:07:33.381Z'), + ten: new Date('2024-11-19T18:52:06.785Z'), + }, + between: new Date('2021-03-15T19:30:57.091Z'), betweens: [ - [ - new Date('2021-03-08T11:09:46.211Z'), - new Date('2021-03-23T05:10:16.500Z'), - new Date('2021-04-06T23:10:46.500Z'), - ], - [ - new Date('2021-03-08T11:09:45.500Z'), - new Date('2021-03-23T05:10:15.500Z'), - new Date('2021-04-06T23:10:45.500Z'), - ], - ], - recent: [ - new Date('2021-02-21T08:11:56.820Z'), - new Date('2021-02-21T08:11:56.109Z'), - ], - soon: [ - new Date('2021-03-13T23:15:38.042Z'), - new Date('2021-03-13T23:15:37.891Z'), + new Date('2021-03-15T19:30:57.091Z'), + new Date('2021-04-09T17:05:10.406Z'), + new Date('2021-04-18T19:23:52.973Z'), ], + recent: new Date('2021-02-21T08:11:56.820Z'), + soon: new Date('2021-03-13T23:15:38.042Z'), month: { - default: 'May', + noArgs: 'May', abbr: 'May', context: 'May', abbr_context: 'May', }, weekday: { - default: 'Tuesday', + noArgs: 'Tuesday', abbr: 'Tue', context: 'Tuesday', abbr_context: 'Tue', @@ -58,50 +38,30 @@ const seededRuns = [ { seed: 1337, expectations: { - past: [ - new Date('2020-11-18T01:49:04.785Z'), - new Date('2020-11-18T01:49:04.074Z'), - new Date('2018-07-11T07:47:33.089Z'), - new Date('2018-07-11T07:47:32.378Z'), - ], - future: [ - new Date('2021-05-28T08:29:26.637Z'), - new Date('2021-05-28T08:29:25.926Z'), - new Date('2023-10-06T02:30:58.333Z'), - new Date('2023-10-06T02:30:57.622Z'), - ], - between: [ - new Date('2021-03-09T04:11:24.667Z'), - new Date('2021-06-12T02:21:47.178Z'), - ], + past: { + noArgs: new Date('2020-11-18T01:49:04.785Z'), + ten: new Date('2018-07-11T07:47:33.089Z'), + }, + future: { + noArgs: new Date('2021-05-28T08:29:26.637Z'), + ten: new Date('2023-10-06T02:30:58.333Z'), + }, + between: new Date('2021-03-09T04:11:24.667Z'), betweens: [ - [ - new Date('2021-03-08T11:09:46.211Z'), - new Date('2021-03-23T05:10:16.500Z'), - new Date('2021-04-06T23:10:46.500Z'), - ], - [ - new Date('2021-03-08T11:09:45.500Z'), - new Date('2021-03-23T05:10:15.500Z'), - new Date('2021-04-06T23:10:45.500Z'), - ], - ], - recent: [ - new Date('2021-02-21T10:53:58.041Z'), - new Date('2021-02-21T10:53:57.330Z'), - ], - soon: [ - new Date('2021-03-13T20:33:36.821Z'), - new Date('2021-03-13T20:33:36.670Z'), + new Date('2021-03-03T01:51:22.512Z'), + new Date('2021-03-09T04:11:24.667Z'), + new Date('2021-03-26T18:53:00.564Z'), ], + recent: new Date('2021-02-21T10:53:58.041Z'), + soon: new Date('2021-03-13T20:33:36.821Z'), month: { - default: 'April', + noArgs: 'April', abbr: 'Apr', context: 'April', abbr_context: 'Apr', }, weekday: { - default: 'Monday', + noArgs: 'Monday', abbr: 'Mon', context: 'Monday', abbr_context: 'Mon', @@ -111,50 +71,30 @@ const seededRuns = [ { seed: 1211, expectations: { - past: [ - new Date('2020-03-19T19:19:04.071Z'), - new Date('2020-03-19T19:19:03.360Z'), - new Date('2011-11-12T14:47:19.955Z'), - new Date('2011-11-12T14:47:19.244Z'), - ], - future: [ - new Date('2022-01-26T14:59:27.351Z'), - new Date('2022-01-26T14:59:26.640Z'), - new Date('2030-06-03T19:31:11.467Z'), - new Date('2030-06-03T19:31:10.756Z'), - ], - between: [ - new Date('2021-04-17T11:58:13.327Z'), - new Date('2022-03-21T16:37:15.905Z'), - ], + past: { + noArgs: new Date('2020-03-19T19:19:04.071Z'), + ten: new Date('2011-11-12T14:47:19.955Z'), + }, + future: { + noArgs: new Date('2022-01-26T14:59:27.351Z'), + ten: new Date('2030-06-03T19:31:11.467Z'), + }, + between: new Date('2021-04-17T11:58:13.327Z'), betweens: [ - [ - new Date('2021-03-08T11:09:46.211Z'), - new Date('2021-03-23T05:10:16.500Z'), - new Date('2021-04-06T23:10:46.500Z'), - ], - [ - new Date('2021-03-08T11:09:45.500Z'), - new Date('2021-03-23T05:10:15.500Z'), - new Date('2021-04-06T23:10:45.500Z'), - ], - ], - recent: [ - new Date('2021-02-20T18:54:13.498Z'), - new Date('2021-02-20T18:54:12.787Z'), - ], - soon: [ - new Date('2021-03-14T12:33:21.364Z'), - new Date('2021-03-14T12:33:21.213Z'), + new Date('2021-03-20T19:08:07.621Z'), // done + new Date('2021-04-15T10:20:25.794Z'), + new Date('2021-04-17T11:58:13.327Z'), ], + recent: new Date('2021-02-20T18:54:13.498Z'), + soon: new Date('2021-03-14T12:33:21.364Z'), month: { - default: 'December', + noArgs: 'December', abbr: 'Dec', context: 'December', abbr_context: 'Dec', }, weekday: { - default: 'Saturday', + noArgs: 'Saturday', abbr: 'Sat', context: 'Saturday', abbr_context: 'Sat', @@ -178,7 +118,7 @@ describe('date', () => { const actual = faker.date.past(undefined, '2021-02-21T17:09:15.711Z'); - expect(actual).toEqual(expectations.past[0]); + expect(actual).toEqual(expectations.past.noArgs); }); it('should return deterministic past value on given refDate of type date', () => { @@ -189,7 +129,7 @@ describe('date', () => { new Date('2021-02-21T17:09:15.711Z') ); - expect(actual).toEqual(expectations.past[1]); + expect(actual).toEqual(expectations.past.noArgs); }); it('should return deterministic past value on given years 10 and refDate of type string', () => { @@ -197,7 +137,7 @@ describe('date', () => { const actual = faker.date.past(10, '2021-02-21T17:09:15.711Z'); - expect(actual).toEqual(expectations.past[2]); + expect(actual).toEqual(expectations.past.ten); }); it('should return deterministic past value on given years 10 and refDate of type date', () => { @@ -208,7 +148,7 @@ describe('date', () => { new Date('2021-02-21T17:09:15.711Z') ); - expect(actual).toEqual(expectations.past[3]); + expect(actual).toEqual(expectations.past.ten); }); }); @@ -221,7 +161,7 @@ describe('date', () => { '2021-02-21T17:09:15.711Z' ); - expect(actual).toEqual(expectations.future[0]); + expect(actual).toEqual(expectations.future.noArgs); }); it('should return deterministic future value on given refDate of type date', () => { @@ -232,7 +172,7 @@ describe('date', () => { new Date('2021-02-21T17:09:15.711Z') ); - expect(actual).toEqual(expectations.future[1]); + expect(actual).toEqual(expectations.future.noArgs); }); it('should return deterministic future value on given years 10 and refDate of type string', () => { @@ -240,7 +180,7 @@ describe('date', () => { const actual = faker.date.future(10, '2021-02-21T17:09:15.711Z'); - expect(actual).toEqual(expectations.future[2]); + expect(actual).toEqual(expectations.future.ten); }); it('should return deterministic future value on given years 10 and refDate of type date', () => { @@ -251,7 +191,7 @@ describe('date', () => { new Date('2021-02-21T17:09:15.711Z') ); - expect(actual).toEqual(expectations.future[3]); + expect(actual).toEqual(expectations.future.ten); }); }); @@ -264,18 +204,18 @@ describe('date', () => { '2021-04-21T17:11:17.711Z' ); - expect(actual).toEqual(expectations.between[0]); + expect(actual).toEqual(expectations.between); }); it('should return deterministic value between given real dates', () => { faker.seed(seed); const actual = faker.date.between( - new Date('2021-02-21'), - new Date('2022-04-21') + new Date('2021-02-21T17:09:15.711Z'), + new Date('2021-04-21T17:11:17.711Z') ); - expect(actual).toEqual(expectations.between[1]); + expect(actual).toEqual(expectations.between); }); }); @@ -283,25 +223,23 @@ describe('date', () => { it('should return deterministic value betweens given string dates', () => { faker.seed(seed); - // TODO @Shinigami92 2022-01-27: This function doesn't respect seeding const actual = faker.date.betweens( '2021-02-21T17:09:15.711Z', '2021-04-21T17:11:17.711Z' ); - expect(actual).toEqual(expectations.betweens[0]); + expect(actual).toEqual(expectations.betweens); }); it('should return deterministic value betweens given dates', () => { faker.seed(seed); - // TODO @Shinigami92 2022-01-27: This function doesn't respect seeding const actual = faker.date.betweens( new Date('2021-02-21T17:09:15.711Z'), new Date('2021-04-21T17:11:17.711Z') ); - expect(actual).toEqual(expectations.betweens[1]); + expect(actual).toEqual(expectations.betweens); }); }); @@ -314,7 +252,7 @@ describe('date', () => { '2021-02-21T17:11:17.711Z' ); - expect(actual).toEqual(expectations.recent[0]); + expect(actual).toEqual(expectations.recent); }); it('should return deterministic value recent to given refDate of type date', () => { @@ -325,7 +263,7 @@ describe('date', () => { new Date('2021-02-21T17:11:17.711Z') ); - expect(actual).toEqual(expectations.recent[1]); + expect(actual).toEqual(expectations.recent); }); }); @@ -335,7 +273,7 @@ describe('date', () => { const actual = faker.date.soon(undefined, '2021-03-13T14:16:17.151Z'); - expect(actual).toEqual(expectations.soon[0]); + expect(actual).toEqual(expectations.soon); }); it('should return deterministic value soon to given refDate of type date', () => { @@ -346,7 +284,7 @@ describe('date', () => { new Date('2021-03-13T14:16:17.151Z') ); - expect(actual).toEqual(expectations.soon[1]); + expect(actual).toEqual(expectations.soon); }); }); @@ -356,7 +294,7 @@ describe('date', () => { const actual = faker.date.month(); - expect(actual).toEqual(expectations.month.default); + expect(actual).toEqual(expectations.month.noArgs); }); it('should return deterministic value month with abbr true', () => { @@ -390,7 +328,7 @@ describe('date', () => { const actual = faker.date.weekday(); - expect(actual).toEqual(expectations.weekday.default); + expect(actual).toEqual(expectations.weekday.noArgs); }); it('should return deterministic value weekday with abbr true', () => { @@ -479,7 +417,13 @@ describe('date', () => { it('should return a date 75 years after the date given', () => { const refDate = new Date(1880, 11, 9, 10, 0, 0, 0); // set the date beyond the usual calculation (to make sure this is working correctly) - const date = faker.date.future(75, refDate.toISOString()); + let date = faker.date.future(75, refDate); + + // date should be after the date given, but before the current time + expect(date).greaterThan(refDate); + expect(date).lessThan(new Date()); + + date = faker.date.future(75, refDate.toISOString()); // date should be after the date given, but before the current time expect(date).greaterThan(refDate); @@ -492,7 +436,12 @@ describe('date', () => { const from = new Date(1990, 5, 7, 9, 11, 0, 0); const to = new Date(2000, 6, 8, 10, 12, 0, 0); - const date = faker.date.between(from, to); + let date = faker.date.between(from, to); + + expect(date).greaterThan(from); + expect(date).lessThan(to); + + date = faker.date.between(from.toISOString(), to.toISOString()); expect(date).greaterThan(from); expect(date).lessThan(to); @@ -504,7 +453,14 @@ describe('date', () => { const from = new Date(1990, 5, 7, 9, 11, 0, 0); const to = new Date(2000, 6, 8, 10, 12, 0, 0); - const dates = faker.date.betweens(from, to); + let dates = faker.date.betweens(from, to); + + expect(dates[0]).greaterThan(from); + expect(dates[0]).lessThan(to); + expect(dates[1]).greaterThan(dates[0]); + expect(dates[2]).greaterThan(dates[1]); + + dates = faker.date.betweens(from.toISOString(), to.toISOString()); expect(dates[0]).greaterThan(from); expect(dates[0]).lessThan(to); @@ -524,12 +480,23 @@ describe('date', () => { const days = 30; const refDate = new Date(2120, 11, 9, 10, 0, 0, 0); // set the date beyond the usual calculation (to make sure this is working correctly) - const date = faker.date.recent(days, refDate); - const lowerBound = new Date( refDate.getTime() - days * 24 * 60 * 60 * 1000 ); + let date = faker.date.recent(days, refDate); + + expect( + lowerBound, + '`recent()` date should not be further back than `n` days ago' + ).lessThanOrEqual(date); + expect( + date, + '`recent()` date should not be ahead of the starting date reference' + ).lessThanOrEqual(refDate); + + date = faker.date.recent(days, refDate.toISOString()); + expect( lowerBound, '`recent()` date should not be further back than `n` days ago' @@ -552,12 +519,23 @@ describe('date', () => { const days = 30; const refDate = new Date(1880, 11, 9, 10, 0, 0, 0); // set the date beyond the usual calculation (to make sure this is working correctly) - const date = faker.date.soon(days, refDate); - const upperBound = new Date( refDate.getTime() + days * 24 * 60 * 60 * 1000 ); + let date = faker.date.soon(days, refDate); + + expect( + date, + '`soon()` date should not be further ahead than `n` days ago' + ).lessThanOrEqual(upperBound); + expect( + refDate, + '`soon()` date should not be behind the starting date reference' + ).lessThanOrEqual(date); + + date = faker.date.soon(days, refDate.toISOString()); + expect( date, '`soon()` date should not be further ahead than `n` days ago' diff --git a/test/fake.spec.ts b/test/fake.spec.ts index d1e18ac484a..a78940eab70 100644 --- a/test/fake.spec.ts +++ b/test/fake.spec.ts @@ -46,5 +46,9 @@ describe('fake', () => { Error('Invalid method: address.foo') ); }); + + it('should be able to return empty strings', () => { + expect(faker.fake('{{helpers.repeatString}}')).toBe(''); + }); }); }); diff --git a/test/finance.spec.ts b/test/finance.spec.ts index d49e29a30f8..312f4fb50dd 100644 --- a/test/finance.spec.ts +++ b/test/finance.spec.ts @@ -384,6 +384,18 @@ describe('finance', () => { expect(luhnCheck(faker.finance.creditCardNumber())).toBeTruthy(); }); + it('should ignore case for provider', () => { + const seed = faker.seedValue; + + faker.seed(seed); + const actualNonLowerCase = faker.finance.creditCardNumber('ViSa'); + + faker.seed(seed); + const actualLowerCase = faker.finance.creditCardNumber('visa'); + + expect(actualNonLowerCase).toBe(actualLowerCase); + }); + it('should return a correct credit card number when issuer provided', () => { //TODO: implement checks for each format with regexp const visa = faker.finance.creditCardNumber('visa'); @@ -417,7 +429,7 @@ describe('finance', () => { expect(luhnCheck(instapayment)).toBeTruthy(); }); - it('should return custom formated strings', () => { + it('should return custom formatted strings', () => { let number = faker.finance.creditCardNumber('###-###-##L'); expect(number).match(/^\d{3}\-\d{3}\-\d{3}$/); expect(luhnCheck(number)).toBeTruthy();