From 591b943f1a17d46374466ac90ca0b9871b135479 Mon Sep 17 00:00:00 2001 From: Richer St-Amand Date: Tue, 23 Apr 2024 15:59:59 -0400 Subject: [PATCH 1/3] fix: generate mock for additional properties without dictionnary --- src/MockGenerateHelper.ts | 29 +++++++++++++++++++++++++++++ src/mockConverter.ts | 7 +++++++ src/types.ts | 5 +++++ 3 files changed, 41 insertions(+) diff --git a/src/MockGenerateHelper.ts b/src/MockGenerateHelper.ts index 61cb6df..541c6b0 100644 --- a/src/MockGenerateHelper.ts +++ b/src/MockGenerateHelper.ts @@ -6,6 +6,7 @@ import { DataTypes, EnumProps, EnumSchema, + GetAdditionalPropertiesProps, GetArrayOfItemsMockProps, GetArrayOfOneOfMockProps, GetDictionaryMockProps, @@ -257,6 +258,34 @@ export class MockGenerateHelper { return { propertyName, value: `" // TODO: Wrong dictionary value",` }; } + getAdditionalPropertiesMock({ propertyName, additionalProperties }: GetAdditionalPropertiesProps): MockArrayProps { + let result: string | Function | undefined = undefined; + + switch (additionalProperties?.type) { + case DataTypes.Integer: + result = () => casual.integer(0, 100); + break; + case DataTypes.Number: + result = () => casual.double(0, 100); + break; + case DataTypes.String: + result = () => casual.string; + break; + case DataTypes.Boolean: + result = 'true'; + break; + case DataTypes.Array: + result = '[]'; + break; + default: { + result = ' // TODO: Wrong dictionary value'; + break; + } + } + + return { propertyName, value: result }; + } + getAnyMock({ propertyName }: { propertyName: string }): MockArrayProps { return { propertyName, diff --git a/src/mockConverter.ts b/src/mockConverter.ts index c619cb9..ae193b0 100644 --- a/src/mockConverter.ts +++ b/src/mockConverter.ts @@ -195,6 +195,13 @@ export const parseSchema = ({ schema, name, DTOs, overrideSchemas }: ParseSchema ); } + if (!xDictionaryKey && additionalProperties && additionalProperties?.type) { + mockGenerator.getAdditionalPropertiesMock({ + propertyName, + additionalProperties, + }); + } + if (!type && !$ref && !oneOf) { mocks.push(mockGenerator.getAnyMock({ propertyName })); } diff --git a/src/types.ts b/src/types.ts index 43c6e05..42c1600 100644 --- a/src/types.ts +++ b/src/types.ts @@ -167,6 +167,11 @@ export interface GetDictionaryMockProps extends PropertyNameProp { overrideSchemas?: Array; } +export interface GetAdditionalPropertiesProps extends PropertyNameProp { + propertyName: string; + additionalProperties: any; +} + export interface GetRefTypeMockProps extends PropertyNameProp { $ref: string; DTOs: any; From 96b2896a1e23c02f9b2b16f55241a3f1337e9bf4 Mon Sep 17 00:00:00 2001 From: Richer St-Amand Date: Tue, 23 Apr 2024 16:03:55 -0400 Subject: [PATCH 2/3] fix: update error message --- src/MockGenerateHelper.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/MockGenerateHelper.ts b/src/MockGenerateHelper.ts index 541c6b0..dba74e0 100644 --- a/src/MockGenerateHelper.ts +++ b/src/MockGenerateHelper.ts @@ -278,7 +278,7 @@ export class MockGenerateHelper { result = '[]'; break; default: { - result = ' // TODO: Wrong dictionary value'; + result = ' // Error: Invalid additionalProperties.type'; break; } } From f6ae79b6b8ca4eba1cf0361219586cbddb619b77 Mon Sep 17 00:00:00 2001 From: Richer St-Amand Date: Tue, 23 Apr 2024 17:38:05 -0400 Subject: [PATCH 3/3] fix: update mock generator and coverage --- src/MockGenerateHelper.ts | 31 ++- src/mockConverter.ts | 12 +- src/types.ts | 2 +- .../__snapshots__/mockConverter.test.ts.snap | 102 ++++++++ tests/mockConverter.test.ts | 229 +++++++++++++++--- 5 files changed, 325 insertions(+), 51 deletions(-) diff --git a/src/MockGenerateHelper.ts b/src/MockGenerateHelper.ts index dba74e0..2c6951f 100644 --- a/src/MockGenerateHelper.ts +++ b/src/MockGenerateHelper.ts @@ -259,31 +259,44 @@ export class MockGenerateHelper { } getAdditionalPropertiesMock({ propertyName, additionalProperties }: GetAdditionalPropertiesProps): MockArrayProps { - let result: string | Function | undefined = undefined; + let hasError: boolean; + let mockValue: string | Function | undefined = undefined; - switch (additionalProperties?.type) { + switch (additionalProperties.type) { case DataTypes.Integer: - result = () => casual.integer(0, 100); + hasError = false; + mockValue = () => casual.integer(0, 100); break; case DataTypes.Number: - result = () => casual.double(0, 100); + hasError = false; + mockValue = () => casual.double(0, 100); break; case DataTypes.String: - result = () => casual.string; + hasError = false; + mockValue = () => `'${casual.string}'`; break; case DataTypes.Boolean: - result = 'true'; + hasError = false; + mockValue = 'true'; break; case DataTypes.Array: - result = '[]'; + hasError = false; + mockValue = '[]'; break; default: { - result = ' // Error: Invalid additionalProperties.type'; + hasError = true; + mockValue = ` /** Error: Invalid additionalProperties.type ${propertyName} */`; break; } } - return { propertyName, value: result }; + const result = typeof mockValue === 'function' ? mockValue() : mockValue; + const value = hasError ? `{\n\t ${result} \n}` : `{\n\t ${casual.word}: ${result}, \n}`; + + return { + propertyName, + value, + }; } getAnyMock({ propertyName }: { propertyName: string }): MockArrayProps { diff --git a/src/mockConverter.ts b/src/mockConverter.ts index ae193b0..5d959cc 100644 --- a/src/mockConverter.ts +++ b/src/mockConverter.ts @@ -195,11 +195,13 @@ export const parseSchema = ({ schema, name, DTOs, overrideSchemas }: ParseSchema ); } - if (!xDictionaryKey && additionalProperties && additionalProperties?.type) { - mockGenerator.getAdditionalPropertiesMock({ - propertyName, - additionalProperties, - }); + if (!xDictionaryKey && additionalProperties) { + mocks.push( + mockGenerator.getAdditionalPropertiesMock({ + propertyName, + additionalProperties, + }), + ); } if (!type && !$ref && !oneOf) { diff --git a/src/types.ts b/src/types.ts index 42c1600..e85df2d 100644 --- a/src/types.ts +++ b/src/types.ts @@ -169,7 +169,7 @@ export interface GetDictionaryMockProps extends PropertyNameProp { export interface GetAdditionalPropertiesProps extends PropertyNameProp { propertyName: string; - additionalProperties: any; + additionalProperties: { type: string }; } export interface GetRefTypeMockProps extends PropertyNameProp { diff --git a/tests/__snapshots__/mockConverter.test.ts.snap b/tests/__snapshots__/mockConverter.test.ts.snap index 089d95e..d071164 100644 --- a/tests/__snapshots__/mockConverter.test.ts.snap +++ b/tests/__snapshots__/mockConverter.test.ts.snap @@ -1,5 +1,107 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP +exports[`Additional properties without dictionary should generate mocks for a type array 1`] = ` +"/* eslint-disable @typescript-eslint/no-use-before-define */ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import {FilterCounters} from './pathToTypes'; + +export const aFilterCountersAPI = (overrides?: Partial): FilterCounters => { + return { + instrumentFilters: { + est: [], +}, + ...overrides, + }; +}; + +" +`; + +exports[`Additional properties without dictionary should generate mocks for a type boolean 1`] = ` +"/* eslint-disable @typescript-eslint/no-use-before-define */ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import {FilterCounters} from './pathToTypes'; + +export const aFilterCountersAPI = (overrides?: Partial): FilterCounters => { + return { + instrumentFilters: { + est: true, +}, + ...overrides, + }; +}; + +" +`; + +exports[`Additional properties without dictionary should generate mocks for a type integer 1`] = ` +"/* eslint-disable @typescript-eslint/no-use-before-define */ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import {FilterCounters} from './pathToTypes'; + +export const aFilterCountersAPI = (overrides?: Partial): FilterCounters => { + return { + instrumentFilters: { + reiciendis: 65, +}, + ...overrides, + }; +}; + +" +`; + +exports[`Additional properties without dictionary should generate mocks for a type invalid 1`] = ` +"/* eslint-disable @typescript-eslint/no-use-before-define */ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import {FilterCounters} from './pathToTypes'; + +export const aFilterCountersAPI = (overrides?: Partial): FilterCounters => { + return { + instrumentFilters: { + /** Error: Invalid additionalProperties.type instrumentFilters */ +}, + ...overrides, + }; +}; + +" +`; + +exports[`Additional properties without dictionary should generate mocks for a type number 1`] = ` +"/* eslint-disable @typescript-eslint/no-use-before-define */ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import {FilterCounters} from './pathToTypes'; + +export const aFilterCountersAPI = (overrides?: Partial): FilterCounters => { + return { + instrumentFilters: { + reiciendis: 64.8914810270071, +}, + ...overrides, + }; +}; + +" +`; + +exports[`Additional properties without dictionary should generate mocks for a type string 1`] = ` +"/* eslint-disable @typescript-eslint/no-use-before-define */ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import {FilterCounters} from './pathToTypes'; + +export const aFilterCountersAPI = (overrides?: Partial): FilterCounters => { + return { + instrumentFilters: { + et: 'est reiciendis dolorum neque voluptatibus quo non', +}, + ...overrides, + }; +}; + +" +`; + exports[`Dictionary type should generate mocks for a "dictionary" type array 1`] = ` "/* eslint-disable @typescript-eslint/no-use-before-define */ /* eslint-disable @typescript-eslint/no-unused-vars */ diff --git a/tests/mockConverter.test.ts b/tests/mockConverter.test.ts index b4be951..c7ed4cf 100644 --- a/tests/mockConverter.test.ts +++ b/tests/mockConverter.test.ts @@ -1768,46 +1768,203 @@ export const aGlobalStateCountersAPI = (overrides?: Partial it('should generate mocks for a "dictionary" type array', async () => { const json = aSwaggerV3Mock({ ComplexDto: { - type: 'object', - additionalProperties: false, - properties: { - name: { - type: 'string', - nullable: true - } - } + type: 'object', + additionalProperties: false, + properties: { + name: { + type: 'string', + nullable: true, + }, + }, }, MainDto: { - type: 'object', - additionalProperties: false, - properties: { - contributors: { - type: 'object', - nullable: true, - 'x-dictionaryKey': { - $ref: '#/components/schemas/Role' - }, - additionalProperties: { - type: 'array', - items: { - $ref: '#/components/schemas/ComplexDto' - } - } - } - } + type: 'object', + additionalProperties: false, + properties: { + contributors: { + type: 'object', + nullable: true, + 'x-dictionaryKey': { + $ref: '#/components/schemas/Role', + }, + additionalProperties: { + type: 'array', + items: { + $ref: '#/components/schemas/ComplexDto', + }, + }, + }, + }, }, Role: { - type: 'string', - 'x-enumNames': [ - 'Role1', - 'Role2', - 'Role3' - ], - enum: [ - 'role1', - 'role2', - 'role3' - ] + type: 'string', + 'x-enumNames': ['Role1', 'Role2', 'Role3'], + enum: ['role1', 'role2', 'role3'], + }, + }); + + const result = await convertToMocks({ + json, + fileName: "doesn't matter", + folderPath: './someFolder', + typesPath: './pathToTypes', + }); + + expect(result).toMatchSnapshot(); + }); +}); + +describe('Additional properties without dictionary', () => { + it('should generate mocks for a type integer', async () => { + const json = aSwaggerV3Mock({ + FilterCounters: { + type: 'object', + additionalProperties: false, + properties: { + instrumentFilters: { + type: 'object', + nullable: true, + additionalProperties: { + type: 'integer', + format: 'int64', + }, + }, + }, + }, + }); + + const result = await convertToMocks({ + json, + fileName: "doesn't matter", + folderPath: './someFolder', + typesPath: './pathToTypes', + }); + + expect(result).toMatchSnapshot(); + }); + + it('should generate mocks for a type number', async () => { + const json = aSwaggerV3Mock({ + FilterCounters: { + type: 'object', + additionalProperties: false, + properties: { + instrumentFilters: { + type: 'object', + nullable: true, + additionalProperties: { + type: 'number', + }, + }, + }, + }, + }); + + const result = await convertToMocks({ + json, + fileName: "doesn't matter", + folderPath: './someFolder', + typesPath: './pathToTypes', + }); + + expect(result).toMatchSnapshot(); + }); + + it('should generate mocks for a type string', async () => { + const json = aSwaggerV3Mock({ + FilterCounters: { + type: 'object', + additionalProperties: false, + properties: { + instrumentFilters: { + type: 'object', + nullable: true, + additionalProperties: { + type: 'string', + }, + }, + }, + }, + }); + + const result = await convertToMocks({ + json, + fileName: "doesn't matter", + folderPath: './someFolder', + typesPath: './pathToTypes', + }); + + expect(result).toMatchSnapshot(); + }); + + it('should generate mocks for a type boolean', async () => { + const json = aSwaggerV3Mock({ + FilterCounters: { + type: 'object', + additionalProperties: false, + properties: { + instrumentFilters: { + type: 'object', + nullable: true, + additionalProperties: { + type: 'boolean', + }, + }, + }, + }, + }); + + const result = await convertToMocks({ + json, + fileName: "doesn't matter", + folderPath: './someFolder', + typesPath: './pathToTypes', + }); + + expect(result).toMatchSnapshot(); + }); + + it('should generate mocks for a type array', async () => { + const json = aSwaggerV3Mock({ + FilterCounters: { + type: 'object', + additionalProperties: false, + properties: { + instrumentFilters: { + type: 'object', + nullable: true, + additionalProperties: { + type: 'array', + }, + }, + }, + }, + }); + + const result = await convertToMocks({ + json, + fileName: "doesn't matter", + folderPath: './someFolder', + typesPath: './pathToTypes', + }); + + expect(result).toMatchSnapshot(); + }); + + it('should generate mocks for a type invalid', async () => { + const json = aSwaggerV3Mock({ + FilterCounters: { + type: 'object', + additionalProperties: false, + properties: { + instrumentFilters: { + type: 'object', + nullable: true, + additionalProperties: { + type: 'a-invalid-type', + }, + }, + }, }, });