From 9b5b08a76494ee419fbd18f7b3ac0d46bede272a Mon Sep 17 00:00:00 2001 From: rezoled Date: Thu, 4 Jul 2024 15:04:30 +0300 Subject: [PATCH 1/5] Refactored the way code is being parsed, removed regex that didn't work well in all cases, implemented JS parser and AST traversing to better handle code --- src/Mock.ts | 11 +- src/utils/MockableFunctionsFinder.ts | 107 ++++++++++++++++-- src/utils/ObjectInspector.ts | 1 + src/utils/ObjectPropertyCodeRetriever.ts | 41 ++++--- test/utils/MockableFunctionsFinder.spec.ts | 9 +- .../utils/ObjectPropertyCodeRetriever.spec.ts | 18 ++- 6 files changed, 145 insertions(+), 42 deletions(-) diff --git a/src/Mock.ts b/src/Mock.ts index 19cf49e..3c5aa06 100644 --- a/src/Mock.ts +++ b/src/Mock.ts @@ -188,12 +188,11 @@ export class Mocker { private processFunctionsCode(object: any): void { this.objectInspector.getObjectPrototypes(object).forEach((obj: any) => { - this.objectInspector.getObjectOwnPropertyNames(obj).forEach((propertyName: string) => { - const functionNames = this.mockableFunctionsFinder.find(this.objectPropertyCodeRetriever.get(obj, propertyName)); - functionNames.forEach((functionName: string) => { - this.createMethodStub(functionName); - this.createInstanceActionListener(functionName, this.clazz.prototype); - }); + const fullClass = this.objectPropertyCodeRetriever.getObject(obj); + const functionNames = this.mockableFunctionsFinder.find(fullClass); + functionNames.forEach((functionName: string) => { + this.createMethodStub(functionName); + this.createInstanceActionListener(functionName, this.clazz.prototype); }); }); } diff --git a/src/utils/MockableFunctionsFinder.ts b/src/utils/MockableFunctionsFinder.ts index 80702e4..fca354d 100644 --- a/src/utils/MockableFunctionsFinder.ts +++ b/src/utils/MockableFunctionsFinder.ts @@ -1,3 +1,96 @@ +import {parse} from "@babel/parser"; +import * as _babel_types from "@babel/types"; + +type FunctionNode = | + _babel_types.ObjectMethod | + _babel_types.ClassMethod | + _babel_types.ClassPrivateMethod | + _babel_types.FunctionDeclaration | + _babel_types.ClassProperty | + _babel_types.Expression | + _babel_types.FunctionExpression; + +const methodTokenName = new Set([ + "ObjectMethod", + "ClassMethod", + "ClassPrivateMethod", + "FunctionDeclaration", + "FunctionExpression" +]); + +const isFunctionNode = (node: _babel_types.Statement | FunctionNode): node is FunctionNode => methodTokenName.has(node.type); + + +function getAssignmentName(node: _babel_types.LVal) { + if (node.type === "Identifier") + return node.name; + + if (node.type === "MemberExpression") { + const prop = node.property; + if (prop.type === 'Identifier') return prop.name; + if (prop.type === 'PrivateName') return prop.id.name; + return null; + } + + return null; +} + +function handleClassProp(node: _babel_types.ClassProperty): string { + if (node.value.type !== 'ArrowFunctionExpression' && node.value.type !== 'FunctionExpression') return null; + + if('name' in node.key) return node.key.name; + if('value' in node.key) return node.key.value.toString(); + return null; +} + +function handleExpression(node: _babel_types.Expression): string { + if ('expression' in node && typeof node.expression !== 'boolean') return handleExpression(node.expression); + + if (node.type === 'AssignmentExpression') { + return getAssignmentName(node.left); + } +} + +function handleVariable(node: _babel_types.VariableDeclaration): string[] { + return node.declarations.filter(n => { + if (n.init.type === 'ArrowFunctionExpression') return true; + if (n.init.type === 'FunctionExpression') return true; + return false; + }).map(n => getAssignmentName(n.id)); +} + +function extractFunctionNames(nodes: (_babel_types.Statement | FunctionNode)[]) { + let names = [] as string[]; + nodes.forEach(node => { + if (isFunctionNode(node)) { + if ('key' in node) { + if ('name' in node.key) + names.push(node.key.name); + if ('value' in node.key) + names.push(node.key.value.toString()); + } + if ('id' in node && node.id) names.push(node.id.name); + } + if ('body' in node) { + names = [...extractFunctionNames(Array.isArray(node.body) ? node.body as _babel_types.Statement[] : [node.body as _babel_types.Statement]), ...names]; + } + + if (node.type === "ExpressionStatement") { + names = [handleExpression(node.expression), ...names]; + } + + if (node.type === "VariableDeclaration") { + names = [...handleVariable(node), ...names]; + } + + if (node.type === "ClassProperty") { + names = [handleClassProp(node), ...extractFunctionNames([node.value]), ...names]; + } + }); + + return names; +} + /** * Looking for all function calls and declarations and provides an array of their names. The mechanism is greedy * and tries to match as many function names as it can find and not only those of inspecting class. @@ -9,18 +102,16 @@ * - [.]functionName = function otherName( */ export class MockableFunctionsFinder { - private functionNameRegex = /[.\s]([^.\s]+?)(?:\(|\s+=\s+(?:function\s*(?:[^.\s]+?\s*)?)?\()/g; - private cleanFunctionNameRegex = /^[.\s]([^.\s]+?)[\s(]/; - private excludedFunctionNames: string[] = ["hasOwnProperty", "function"]; + private excludedFunctionNames = new Set(["hasOwnProperty", "function"]); public find(code: string): string[] { - return (code.match(this.functionNameRegex) || []) - .map((match: string) => match.match(this.cleanFunctionNameRegex)[1]) - .filter((functionName: string) => this.isMockable(functionName)) - .map((functionName: string) => functionName.indexOf('=') > 0 ? functionName.substr(0, functionName.indexOf('=')) : functionName); + const ast = parse(code); + const names = extractFunctionNames(ast.program.body); + return names + .filter((functionName: string) => this.isMockable(functionName)); } private isMockable(name: string): boolean { - return this.excludedFunctionNames.indexOf(name) < 0; + return !this.excludedFunctionNames.has(name); } } diff --git a/src/utils/ObjectInspector.ts b/src/utils/ObjectInspector.ts index 79b8f7d..7406477 100644 --- a/src/utils/ObjectInspector.ts +++ b/src/utils/ObjectInspector.ts @@ -1,5 +1,6 @@ import * as _ from "lodash"; + export class ObjectInspector { public getObjectPrototypes(prototype: any): any[] { const prototypes: any[] = []; diff --git a/src/utils/ObjectPropertyCodeRetriever.ts b/src/utils/ObjectPropertyCodeRetriever.ts index 4551024..b0e05f5 100644 --- a/src/utils/ObjectPropertyCodeRetriever.ts +++ b/src/utils/ObjectPropertyCodeRetriever.ts @@ -1,17 +1,32 @@ export class ObjectPropertyCodeRetriever { - public get(object: any, propertyName: string): string { - const descriptor = Object.getOwnPropertyDescriptor(object, propertyName); - if (!descriptor) { - // property is defined in prototype but has no descriptor (it comes from abstract class and was not override) - return ""; + public getObject(object: any) { + const props = Object.getOwnPropertyNames(object); + return `class Prototype { + ${props.map(prop => { + let result = ''; + const descriptor = Object.getOwnPropertyDescriptor(object, prop); + if (descriptor.get) { + result += ` + ${descriptor.get.toString()} + `; + } + if (descriptor.set) { + result += ` + ${descriptor.set.toString()} + `; + } + if (!descriptor.get && !descriptor.set && typeof object[prop] === 'function') { + const propName = prop === 'constructor' ? 'mock_constructor' : prop; + result += ` + ${propName} = ${String(object[prop])} + `; + } + + return result; + }).join(` + `)} } - const accessorsCodes = []; - if (descriptor.get) { - accessorsCodes.push(descriptor.get.toString()); - } - if (descriptor.set) { - accessorsCodes.push(descriptor.set.toString()); - } - return accessorsCodes.join(" ") || String(object[propertyName]); + `; } + } diff --git a/test/utils/MockableFunctionsFinder.spec.ts b/test/utils/MockableFunctionsFinder.spec.ts index 894d0f7..7256bda 100644 --- a/test/utils/MockableFunctionsFinder.spec.ts +++ b/test/utils/MockableFunctionsFinder.spec.ts @@ -10,9 +10,8 @@ describe("MockableFunctionsFinder", () => { const result = new MockableFunctionsFinder().find(code); // then - expect(result).toContain("log"); - expect(result).toContain("toString"); expect(result).toContain("anonymousMethod"); + expect(result).toContain("convertNumberToString"); }); it("should not find hasOwnProperty as it should not be mocked (because its used by mockito to evaluate properties)", () => { @@ -30,15 +29,15 @@ describe("MockableFunctionsFinder", () => { function getSampleCode(): string { return ` -export class Foo { - constructor (private temp:string) { +class Foo { + constructor (temp) { this.anonymousMethod = function(arg) { console.log(arg); temp.hasOwnProperty("fakeProperty"); } } - private convertNumberToString(value:number):string { + convertNumberToString(value) { return value.toString(); } } diff --git a/test/utils/ObjectPropertyCodeRetriever.spec.ts b/test/utils/ObjectPropertyCodeRetriever.spec.ts index 139c23c..49e6ab5 100644 --- a/test/utils/ObjectPropertyCodeRetriever.spec.ts +++ b/test/utils/ObjectPropertyCodeRetriever.spec.ts @@ -22,22 +22,20 @@ describe("ObjectPropertyCodeRetriever", () => { }; }); - it("Provides code of given existing property", () => { - expect(objectPropertyCodeRetriever.get(object, "undefinedProperty")).toBe("undefined"); - expect(objectPropertyCodeRetriever.get(object, "nullProperty")).toBe("null"); - expect(objectPropertyCodeRetriever.get(object, "nanProperty")).toBe("NaN"); - expect(objectPropertyCodeRetriever.get(object, "stringProperty")).toBe("stringProperty"); - expect(objectPropertyCodeRetriever.get(object, "booleanProperty")).toBe("true"); - expect(objectPropertyCodeRetriever.get(object, "testMethod")).toMatch(/function \(\)/); + it("Provides code of given existing property method", () => { + const objStr = objectPropertyCodeRetriever.getObject(object); + expect(objStr).toContain('testMethod = function () { return true; }'); }); it("Provides code of given existing property accessors", () => { - expect(objectPropertyCodeRetriever.get(object, "someValue")).toMatch(/return "someValue"/); - expect(objectPropertyCodeRetriever.get(object, "someValue")).toMatch(/console\.info\("someValue set"\)/); + const objStr = objectPropertyCodeRetriever.getObject(object); + expect(objStr).toMatch(/get someValue\(\) \{\s*return "someValue";\s*}/); + expect(objStr).toMatch(/set someValue\(newValue\) \{\s*console.info\("someValue set"\);\s*}/); }); it("Returns empty string when checking non existent property", () => { - expect(objectPropertyCodeRetriever.get(object, "nonExistentProperty")).toBe(""); + const objStr = objectPropertyCodeRetriever.getObject(object); + expect(objStr).not.toContain("nonExistentProperty"); }); }); }); From b51b12b5b9d79f33d23381945a04bd02bc04bacd Mon Sep 17 00:00:00 2001 From: rezoled Date: Sun, 14 Jul 2024 14:36:40 +0300 Subject: [PATCH 2/5] 2.6.8 --- package-lock.json | 4 +- package.json | 2 +- .../utils/ObjectPropertyCodeRetriever.spec.ts | 41 ------------------- 3 files changed, 3 insertions(+), 44 deletions(-) delete mode 100644 test/utils/ObjectPropertyCodeRetriever.spec.ts diff --git a/package-lock.json b/package-lock.json index 222f4fd..f01799c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@typestrong/ts-mockito", - "version": "2.6.7", + "version": "2.6.8", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@typestrong/ts-mockito", - "version": "2.6.7", + "version": "2.6.8", "license": "MIT", "dependencies": { "@babel/parser": "^7.24.7", diff --git a/package.json b/package.json index 7ebfc80..09f353b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@typestrong/ts-mockito", - "version": "2.6.7", + "version": "2.6.8", "description": "Mocking library for TypeScript", "main": "lib/ts-mockito.js", "typings": "lib/ts-mockito", diff --git a/test/utils/ObjectPropertyCodeRetriever.spec.ts b/test/utils/ObjectPropertyCodeRetriever.spec.ts deleted file mode 100644 index 49e6ab5..0000000 --- a/test/utils/ObjectPropertyCodeRetriever.spec.ts +++ /dev/null @@ -1,41 +0,0 @@ -import {ObjectPropertyCodeRetriever} from "../../src/utils/ObjectPropertyCodeRetriever"; - -describe("ObjectPropertyCodeRetriever", () => { - describe("Properties code retrieving", () => { - const objectPropertyCodeRetriever: ObjectPropertyCodeRetriever = new ObjectPropertyCodeRetriever(); - let object: any; - - beforeEach(() => { - object = { - undefinedProperty: undefined, - nullProperty: null, - nanProperty: NaN, - stringProperty: "stringProperty", - booleanProperty: true, - testMethod: () => true, - get someValue(): string { - return "someValue"; - }, - set someValue(newValue: string) { - console.info("someValue set"); - }, - }; - }); - - it("Provides code of given existing property method", () => { - const objStr = objectPropertyCodeRetriever.getObject(object); - expect(objStr).toContain('testMethod = function () { return true; }'); - }); - - it("Provides code of given existing property accessors", () => { - const objStr = objectPropertyCodeRetriever.getObject(object); - expect(objStr).toMatch(/get someValue\(\) \{\s*return "someValue";\s*}/); - expect(objStr).toMatch(/set someValue\(newValue\) \{\s*console.info\("someValue set"\);\s*}/); - }); - - it("Returns empty string when checking non existent property", () => { - const objStr = objectPropertyCodeRetriever.getObject(object); - expect(objStr).not.toContain("nonExistentProperty"); - }); - }); -}); From 3b7c114d7f8518cc65a902f328f4ec6ac550f8d7 Mon Sep 17 00:00:00 2001 From: rezoled Date: Sun, 14 Jul 2024 16:21:19 +0300 Subject: [PATCH 3/5] fixed the way class object inheritance tree code is being created. fixed tests to be more consistent and not rely on compilation result. --- src/Mock.ts | 22 ++------ src/utils/MockableFunctionsFinder.ts | 25 ++++++--- src/utils/ObjectInspector.ts | 4 +- src/utils/ObjectPropertyCodeRetriever.ts | 10 ++-- test/utils/MockableFunctionsFinder.spec.ts | 63 +++++++++++++++++++++- test/utils/ObjectInspector.spec.ts | 10 ++-- 6 files changed, 94 insertions(+), 40 deletions(-) diff --git a/src/Mock.ts b/src/Mock.ts index 3c5aa06..ee83e6a 100644 --- a/src/Mock.ts +++ b/src/Mock.ts @@ -8,15 +8,12 @@ import {ReturnValueMethodStub} from "./stub/ReturnValueMethodStub"; import {strictEqual} from "./ts-mockito"; import {MockableFunctionsFinder} from "./utils/MockableFunctionsFinder"; import {ObjectInspector} from "./utils/ObjectInspector"; -import {ObjectPropertyCodeRetriever} from "./utils/ObjectPropertyCodeRetriever"; export class Mocker { public mock: any = {}; - protected objectInspector = new ObjectInspector(); private methodStubCollections: any = {}; private methodActions: MethodAction[] = []; private mockableFunctionsFinder = new MockableFunctionsFinder(); - private objectPropertyCodeRetriever = new ObjectPropertyCodeRetriever(); private excludedPropertyNames: string[] = ["hasOwnProperty"]; private defaultedPropertyNames: string[] = ["Symbol(Symbol.toPrimitive)", "then", "catch"]; @@ -27,7 +24,6 @@ export class Mocker { this.processProperties((this.clazz as any).prototype); if (!isSpy || typeof Proxy === "undefined") { this.processClassCode(this.clazz); - this.processFunctionsCode((this.clazz as any).prototype); } } if (typeof Proxy !== "undefined" && this.clazz) { @@ -123,8 +119,8 @@ export class Mocker { } protected processProperties(object: any): void { - this.objectInspector.getObjectPrototypes(object).forEach((obj: any) => { - this.objectInspector.getObjectOwnPropertyNames(obj).forEach((name: string) => { + ObjectInspector.getObjectPrototypes(object).forEach((obj: any) => { + ObjectInspector.getObjectOwnPropertyNames(obj).forEach((name: string) => { if (this.excludedPropertyNames.indexOf(name) >= 0) { return; } @@ -178,25 +174,13 @@ export class Mocker { } private processClassCode(clazz: any): void { - const classCode = typeof clazz.toString !== "undefined" ? clazz.toString() : ""; - const functionNames = this.mockableFunctionsFinder.find(classCode); + const functionNames = this.mockableFunctionsFinder.find(clazz); functionNames.forEach((functionName: string) => { this.createMethodStub(functionName); this.createInstanceActionListener(functionName, this.clazz.prototype); }); } - private processFunctionsCode(object: any): void { - this.objectInspector.getObjectPrototypes(object).forEach((obj: any) => { - const fullClass = this.objectPropertyCodeRetriever.getObject(obj); - const functionNames = this.mockableFunctionsFinder.find(fullClass); - functionNames.forEach((functionName: string) => { - this.createMethodStub(functionName); - this.createInstanceActionListener(functionName, this.clazz.prototype); - }); - }); - } - private createPropertyStub(key: string): void { if (this.mock.hasOwnProperty(key)) { return; diff --git a/src/utils/MockableFunctionsFinder.ts b/src/utils/MockableFunctionsFinder.ts index fca354d..84569c7 100644 --- a/src/utils/MockableFunctionsFinder.ts +++ b/src/utils/MockableFunctionsFinder.ts @@ -1,5 +1,8 @@ import {parse} from "@babel/parser"; import * as _babel_types from "@babel/types"; +import {ObjectInspector} from "./ObjectInspector"; +import {ObjectPropertyCodeRetriever} from "./ObjectPropertyCodeRetriever"; +import {uniq} from "lodash"; type FunctionNode = | _babel_types.ObjectMethod | @@ -38,8 +41,8 @@ function getAssignmentName(node: _babel_types.LVal) { function handleClassProp(node: _babel_types.ClassProperty): string { if (node.value.type !== 'ArrowFunctionExpression' && node.value.type !== 'FunctionExpression') return null; - if('name' in node.key) return node.key.name; - if('value' in node.key) return node.key.value.toString(); + if ('name' in node.key) return node.key.name; + if ('value' in node.key) return node.key.value.toString(); return null; } @@ -84,7 +87,7 @@ function extractFunctionNames(nodes: (_babel_types.Statement | FunctionNode)[]) } if (node.type === "ClassProperty") { - names = [handleClassProp(node), ...extractFunctionNames([node.value]), ...names]; + names = [handleClassProp(node), ...extractFunctionNames([node.value]), ...names]; } }); @@ -104,14 +107,20 @@ function extractFunctionNames(nodes: (_babel_types.Statement | FunctionNode)[]) export class MockableFunctionsFinder { private excludedFunctionNames = new Set(["hasOwnProperty", "function"]); - public find(code: string): string[] { - const ast = parse(code); - const names = extractFunctionNames(ast.program.body); - return names + public find(clazz: any): string[] { + const codes = this.getClassCodeAsStringWithInheritance(clazz); + const names = codes.map(code => parse(code)).flatMap(ast => extractFunctionNames(ast.program.body)); + return uniq(names) .filter((functionName: string) => this.isMockable(functionName)); } - private isMockable(name: string): boolean { + private isMockable(name: string | null | undefined): boolean { + if (!name) return false; return !this.excludedFunctionNames.has(name); } + + private getClassCodeAsStringWithInheritance(clazz: any) { + const classCode: string = typeof clazz.toString !== "undefined" ? clazz.toString() : ""; + return [classCode, ...ObjectInspector.getObjectPrototypes(clazz.prototype).map(ObjectPropertyCodeRetriever.getObject)]; + } } diff --git a/src/utils/ObjectInspector.ts b/src/utils/ObjectInspector.ts index 7406477..ec8c1ad 100644 --- a/src/utils/ObjectInspector.ts +++ b/src/utils/ObjectInspector.ts @@ -2,7 +2,7 @@ import * as _ from "lodash"; export class ObjectInspector { - public getObjectPrototypes(prototype: any): any[] { + public static getObjectPrototypes(prototype: any): any[] { const prototypes: any[] = []; while (_.isObject(prototype) && (prototype !== Object.prototype && prototype !== Function.prototype)) { prototypes.push(prototype); @@ -11,7 +11,7 @@ export class ObjectInspector { return prototypes; } - public getObjectOwnPropertyNames(object: any): string[] { + public static getObjectOwnPropertyNames(object: any): string[] { return _.isObject(object) ? Object.getOwnPropertyNames(object) : []; } } diff --git a/src/utils/ObjectPropertyCodeRetriever.ts b/src/utils/ObjectPropertyCodeRetriever.ts index b0e05f5..67a5dd1 100644 --- a/src/utils/ObjectPropertyCodeRetriever.ts +++ b/src/utils/ObjectPropertyCodeRetriever.ts @@ -1,7 +1,8 @@ + export class ObjectPropertyCodeRetriever { - public getObject(object: any) { + public static getObject(object: any) { const props = Object.getOwnPropertyNames(object); - return `class Prototype { + return `class ${object.constructor.name} { ${props.map(prop => { let result = ''; const descriptor = Object.getOwnPropertyDescriptor(object, prop); @@ -16,9 +17,10 @@ export class ObjectPropertyCodeRetriever { `; } if (!descriptor.get && !descriptor.set && typeof object[prop] === 'function') { - const propName = prop === 'constructor' ? 'mock_constructor' : prop; + const propName = prop === 'constructor' ? 'mock_constructor' : ''; + const fnStr = String(object[prop]); result += ` - ${propName} = ${String(object[prop])} + ${propName ? propName + '=' : ''}${fnStr} `; } diff --git a/test/utils/MockableFunctionsFinder.spec.ts b/test/utils/MockableFunctionsFinder.spec.ts index 7256bda..a37a8d8 100644 --- a/test/utils/MockableFunctionsFinder.spec.ts +++ b/test/utils/MockableFunctionsFinder.spec.ts @@ -25,10 +25,36 @@ describe("MockableFunctionsFinder", () => { expect(result["hasOwnProperty"] instanceof Function).toBeTruthy(); }); }); + + describe("searching for method names in complex class code", () => { + const mockableFunctionsFinder = new MockableFunctionsFinder(); + let mockableMethods: string[]; + + beforeEach(() => { + // tslint:disable-next-line:no-eval + const object = getSampleComplexClassCode(); + mockableMethods = mockableFunctionsFinder.find(object); + }); + + it("should find existing property method", () => { + expect(mockableMethods).toContain('testMethod'); + expect(mockableMethods).toContain('testMethod2'); + expect(mockableMethods).toContain('testMethod3'); + }); + + it("should find existing existing property accessors", () => { + expect(mockableMethods).toContain('someValue'); + }); + + it("should not find non existent property", () => { + expect(mockableMethods).not.toContain("nonExistentProperty"); + }); + }); }); function getSampleCode(): string { - return ` + // tslint:disable-next-line:no-eval + return eval(` class Foo { constructor (temp) { this.anonymousMethod = function(arg) { @@ -41,5 +67,38 @@ class Foo { return value.toString(); } } -`; + +Foo; +`); } + +function getSampleComplexClassCode() { + // tslint:disable-next-line:no-eval + return eval(` +class InheritedTest { + undefinedProperty = undefined; + nullProperty = null; + nanProperty = NaN; + stringProperty = "stringProperty"; + booleanProperty = true; + testMethod = () => true; + testMethod2 = function () { return true }; + + get someValue() { + return "someValue"; + } + + set someValue(newValue) { + console.info("someValue set"); + } +} + +class Test extends InheritedTest { + testMethod3() { + return 'barbaz'; + } +} + +Test; +`) +} \ No newline at end of file diff --git a/test/utils/ObjectInspector.spec.ts b/test/utils/ObjectInspector.spec.ts index 6102280..b0abc3a 100644 --- a/test/utils/ObjectInspector.spec.ts +++ b/test/utils/ObjectInspector.spec.ts @@ -8,7 +8,7 @@ describe("ObjectInspector", () => { let methodNames: string[] = []; // when - new ObjectInspector().getObjectPrototypes(ChildClass.prototype).forEach((obj: any) => { + ObjectInspector.getObjectPrototypes(ChildClass.prototype).forEach((obj: any) => { methodNames = _.union(methodNames, Object.getOwnPropertyNames(obj)); }); @@ -23,7 +23,7 @@ describe("ObjectInspector", () => { let called = false; // when - new ObjectInspector().getObjectPrototypes(null).forEach((obj: any) => { + ObjectInspector.getObjectPrototypes(null).forEach((obj: any) => { called = true; }); @@ -38,7 +38,7 @@ describe("ObjectInspector", () => { let propertyNames: string[] = []; // when - new ObjectInspector().getObjectOwnPropertyNames(ParentClass.prototype).forEach((property: any) => { + ObjectInspector.getObjectOwnPropertyNames(ParentClass.prototype).forEach((property: any) => { propertyNames = _.union(propertyNames, [property]); }); @@ -47,12 +47,12 @@ describe("ObjectInspector", () => { expect(propertyNames).toContain("sampleBoolean"); }); - it("provides an empty array for non object passed (doesn't throw en excpetion)", () => { + it("provides an empty array for non object passed (doesn't throw en exception)", () => { // given let called = false; // when - new ObjectInspector().getObjectOwnPropertyNames(null).forEach((obj: any) => { + ObjectInspector.getObjectOwnPropertyNames(null).forEach((obj: any) => { called = true; }); From b9874476b0357dd572d47f32dc1da6c4e5a0e62f Mon Sep 17 00:00:00 2001 From: rezoled Date: Sun, 14 Jul 2024 16:29:05 +0300 Subject: [PATCH 4/5] fixed lint --- src/utils/ObjectPropertyCodeRetriever.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/ObjectPropertyCodeRetriever.ts b/src/utils/ObjectPropertyCodeRetriever.ts index 67a5dd1..4792fda 100644 --- a/src/utils/ObjectPropertyCodeRetriever.ts +++ b/src/utils/ObjectPropertyCodeRetriever.ts @@ -20,7 +20,7 @@ export class ObjectPropertyCodeRetriever { const propName = prop === 'constructor' ? 'mock_constructor' : ''; const fnStr = String(object[prop]); result += ` - ${propName ? propName + '=' : ''}${fnStr} + ${propName ? `${propName}=` : ''}${fnStr} `; } From a8a29ba16dc41ffbfb638f75cad7c4f338fbb4b3 Mon Sep 17 00:00:00 2001 From: rezoled Date: Sun, 14 Jul 2024 16:31:28 +0300 Subject: [PATCH 5/5] fixed lint --- test/utils/MockableFunctionsFinder.spec.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/utils/MockableFunctionsFinder.spec.ts b/test/utils/MockableFunctionsFinder.spec.ts index a37a8d8..2481295 100644 --- a/test/utils/MockableFunctionsFinder.spec.ts +++ b/test/utils/MockableFunctionsFinder.spec.ts @@ -100,5 +100,5 @@ class Test extends InheritedTest { } Test; -`) +`); } \ No newline at end of file