diff --git a/src/modules/fake/index.ts b/src/modules/fake/index.ts index a9f2a22a173..a94d8845279 100644 --- a/src/modules/fake/index.ts +++ b/src/modules/fake/index.ts @@ -88,16 +88,29 @@ export class Fake { // split the method into module and function const parts = method.split('.'); - if (this.faker[parts[0]] == null) { - throw new FakerError(`Invalid module: ${parts[0]}`); + let currentModuleOrMethod: unknown = this.faker; + let currentDefinitions: unknown = this.faker.definitions; + + // Search for the requested method or definition + for (const part of parts) { + currentModuleOrMethod = currentModuleOrMethod?.[part]; + currentDefinitions = currentDefinitions?.[part]; } - if (this.faker[parts[0]][parts[1]] == null) { - throw new FakerError(`Invalid method: ${parts[0]}.${parts[1]}`); + // Make method executable + let fn: (args?: unknown) => unknown; + if (typeof currentModuleOrMethod === 'function') { + fn = currentModuleOrMethod as (args?: unknown) => unknown; + } else if (Array.isArray(currentDefinitions)) { + fn = () => + this.faker.helpers.arrayElement(currentDefinitions as unknown[]); + } else { + throw new FakerError(`Invalid module method or definition: ${method} +- faker.${method} is not a function +- faker.definitions.${method} is not an array`); } // assign the function from the module.function namespace - let fn: (args?: unknown) => string = this.faker[parts[0]][parts[1]]; fn = fn.bind(this); // If parameters are populated here, they are always going to be of string type diff --git a/test/fake.spec.ts b/test/fake.spec.ts index 2846b9ee9c0..c9ce3b31790 100644 --- a/test/fake.spec.ts +++ b/test/fake.spec.ts @@ -38,13 +38,33 @@ describe('fake', () => { it('does not allow invalid module name', () => { expect(() => faker.fake('{{foo.bar}}')).toThrowError( - new FakerError('Invalid module: foo') + new FakerError(`Invalid module method or definition: foo.bar +- faker.foo.bar is not a function +- faker.definitions.foo.bar is not an array`) + ); + }); + + it('does not allow missing method name', () => { + expect(() => faker.fake('{{address}}')).toThrowError( + new FakerError(`Invalid module method or definition: address +- faker.address is not a function +- faker.definitions.address is not an array`) ); }); it('does not allow invalid method name', () => { expect(() => faker.fake('{{address.foo}}')).toThrowError( - new FakerError('Invalid method: address.foo') + new FakerError(`Invalid module method or definition: address.foo +- faker.address.foo is not a function +- faker.definitions.address.foo is not an array`) + ); + }); + + it('does not allow invalid definitions data', () => { + expect(() => faker.fake('{{finance.credit_card}}')).toThrowError( + new FakerError(`Invalid module method or definition: finance.credit_card +- faker.finance.credit_card is not a function +- faker.definitions.finance.credit_card is not an array`) ); }); @@ -52,6 +72,18 @@ describe('fake', () => { expect(faker.fake('{{helpers.repeatString}}')).toBe(''); }); + it('should be able to return locale definition strings', () => { + expect(faker.definitions.cell_phone.formats).toContain( + faker.fake('{{cell_phone.formats}}') + ); + }); + + it('should be able to return locale definition strings that starts with the name of an existing module', () => { + expect(faker.definitions.address.city_name).toContain( + faker.fake('{{address.city_name}}') + ); + }); + it('should be able to handle only {{ brackets', () => { expect(faker.fake('{{hello')).toBe('{{hello'); expect(faker.fake('hello{{')).toBe('hello{{');