From cd50715c27d9fdb55a32b208357f07568d7ce82e Mon Sep 17 00:00:00 2001 From: Elijah Mugo Date: Fri, 1 Nov 2024 20:31:59 +0300 Subject: [PATCH] fix(zod-mock): [#172] add support for mockeryMapper to be used for numbers, dates and booleans --- packages/zod-mock/src/lib/zod-mock.spec.ts | 56 +++++++++++++++++++++- packages/zod-mock/src/lib/zod-mock.ts | 32 +++++++++++++ 2 files changed, 87 insertions(+), 1 deletion(-) diff --git a/packages/zod-mock/src/lib/zod-mock.spec.ts b/packages/zod-mock/src/lib/zod-mock.spec.ts index ded6065..cb2aaa4 100644 --- a/packages/zod-mock/src/lib/zod-mock.spec.ts +++ b/packages/zod-mock/src/lib/zod-mock.spec.ts @@ -1,6 +1,7 @@ import { z } from 'zod'; import { generateMock, ZodMockError } from './zod-mock'; -import { faker } from '@faker-js/faker'; +import { faker, Faker } from '@faker-js/faker'; +import { FakerFunction } from './zod-mockery-map'; describe('zod-mock', () => { it('should generate a mock object using faker', () => { @@ -734,4 +735,57 @@ describe('zod-mock', () => { expect(mockedFlight.operating_airline.departure.time).toBeInstanceOf(Date); expect(mockedFlight.operating_airline.flightNumber.length).toBeLessThan(5); }); + + describe('mockeryMapper', () => { + const quota = z.object({ + id: z.number(), + created: z.date(), + territoryName: z.string(), + enabled: z.boolean(), + }); + + const mockeryMapper = ( + keyName: string, + fakerInstance: Faker + ): FakerFunction | undefined => { + const keyToFnMap: Record = { + id: () => fakerInstance.number.int({ min: 3, max: 22 }), + enabled: () => fakerInstance.datatype.boolean({ probability: 1 }), + territoryName: () => fakerInstance.string.fromCharacters('abcdef', 20), + created: () => fakerInstance.date.past(), + }; + return keyName && keyName.toLowerCase() in keyToFnMap + ? keyToFnMap[keyName.toLowerCase() as never] + : undefined; + }; + + // generate multiple records to ensure consistency + const mockedQuotas = generateMock(quota.array().length(10), { + mockeryMapper, + }); + + describe.each(mockedQuotas)( + '%#. quota with id $id mock data unit tests', + (mockedQuota, index) => { + it(`uses the id faker function in the mockeryMapper to generate ${mockedQuota.id}`, () => { + // the value should always be in the range [3, 22] as pert hge mockery mapper function + expect(mockedQuota.id).toBeGreaterThanOrEqual(3); + expect(mockedQuota.id).toBeLessThanOrEqual(22); + }); + + it(`uses the enabled faker function in the mockeryMapper to generate ${mockedQuota.enabled}`, () => { + // the value should always be true as per the mockery mapper function + expect(mockedQuota.enabled).toBe(true); + }); + + it(`uses the created faker function in the mockeryMapper to generate ${mockedQuota.created.toISOString()}`, () => { + // the date should always be in the past as per the mockery mapper function + expect(mockedQuota.created).toBeInstanceOf(Date); + expect(mockedQuota.created.getTime()).toBeLessThan( + new Date().getTime() + ); + }); + } + ); + }); }); diff --git a/packages/zod-mock/src/lib/zod-mock.ts b/packages/zod-mock/src/lib/zod-mock.ts index 31ebdeb..ad36ed8 100644 --- a/packages/zod-mock/src/lib/zod-mock.ts +++ b/packages/zod-mock/src/lib/zod-mock.ts @@ -121,6 +121,21 @@ function findMatchingFaker( } } +/** + * Generate mock value from a matching faker function extracted from the mockeryMapper + * @param options mock generator options + * @returns a mock value if a faker function is found in the mockeryMapper passed + */ +function generateMockFromMatchingFaker(options?: GenerateMockOptions) { + // check if there exists a faker for the given key in the mockery mapper + const foundMockeryMapperFaker = options?.keyName + ? findMatchingFaker(options?.keyName, options.faker, options.mockeryMapper) + : undefined; + + // generate the mock value from the faker function found + return foundMockeryMapperFaker?.() ?? undefined; +} + function parseString( zodRef: z.ZodString, options?: GenerateMockOptions @@ -265,6 +280,12 @@ function parseString( function parseBoolean(zodRef: z.ZodBoolean, options?: GenerateMockOptions) { const fakerInstance = options?.faker || faker; + + // generate the mock boolean from the mockery mapper + const mockBoolean = generateMockFromMatchingFaker(options); + // verify that the return type of the mock data is a boolean for it to be acceptable + if (typeof mockBoolean === 'boolean') return mockBoolean; + return fakerInstance.datatype.boolean(); } @@ -285,6 +306,11 @@ function parseDate(zodRef: z.ZodDate, options?: GenerateMockOptions) { } }); + // generate the mock date from the mockery mapper + const mockDate = generateMockFromMatchingFaker(options); + // verify that the return type of the mock data is a valid date for it to be acceptable + if (mockDate instanceof Date) return mockDate; + if (min !== undefined && max !== undefined) { return fakerInstance.date.between({ from: min, to: max }); } else if (min !== undefined && max === undefined) { @@ -316,6 +342,12 @@ function parseNumber( break; } }); + + // generate the mock number from the mockeryMapper + const mockNumber = generateMockFromMatchingFaker(options); + // verify that the return type of the mock data is a number for it to be acceptable + if (typeof mockNumber === 'number') return mockNumber; + return fakerInstance.number.int(fakerOptions); }