From 07ef837bf86dbf7198e488d463e4157e42d36605 Mon Sep 17 00:00:00 2001 From: rezoled Date: Sun, 14 Jul 2024 17:19:35 +0300 Subject: [PATCH 1/5] 2.6.8 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) 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", From 387124f58568089755003ed513fb59e0479b1dd9 Mon Sep 17 00:00:00 2001 From: rezoled Date: Mon, 15 Jul 2024 11:20:30 +0300 Subject: [PATCH 2/5] 2.6.9 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index f01799c..c8acbb2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@typestrong/ts-mockito", - "version": "2.6.8", + "version": "2.6.9", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@typestrong/ts-mockito", - "version": "2.6.8", + "version": "2.6.9", "license": "MIT", "dependencies": { "@babel/parser": "^7.24.7", diff --git a/package.json b/package.json index 09f353b..0d50f40 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@typestrong/ts-mockito", - "version": "2.6.8", + "version": "2.6.9", "description": "Mocking library for TypeScript", "main": "lib/ts-mockito.js", "typings": "lib/ts-mockito", From 5ee56718d1f6a329fc12465b934c8e9c54cc1271 Mon Sep 17 00:00:00 2001 From: rezoled Date: Mon, 15 Jul 2024 11:20:48 +0300 Subject: [PATCH 3/5] 2.7.1 --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index c8acbb2..9508fec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@typestrong/ts-mockito", - "version": "2.6.9", + "version": "2.7.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@typestrong/ts-mockito", - "version": "2.6.9", + "version": "2.7.1", "license": "MIT", "dependencies": { "@babel/parser": "^7.24.7", diff --git a/package.json b/package.json index 0d50f40..42d1948 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@typestrong/ts-mockito", - "version": "2.6.9", + "version": "2.7.1", "description": "Mocking library for TypeScript", "main": "lib/ts-mockito.js", "typings": "lib/ts-mockito", From 6472f1a7ea9bb785f04a8da6f4a4bd98881b0571 Mon Sep 17 00:00:00 2001 From: rezoled Date: Mon, 15 Jul 2024 11:21:35 +0300 Subject: [PATCH 4/5] strict null checks --- src/MethodStubCollection.ts | 6 +++--- src/MethodStubSetter.ts | 2 +- src/Mock.ts | 10 ++++----- src/Spy.ts | 4 ++-- src/matcher/type/DeepEqualMatcher.ts | 2 +- src/spy/RealMethod.ts | 2 +- src/tsconfig.json | 1 + src/utils/MockableFunctionsFinder.ts | 24 +++++++++++++-------- src/utils/ObjectPropertyCodeRetriever.ts | 10 ++++----- test/matcher/type/AnyOfClassMatcher.spec.ts | 1 + test/matcher/type/DeepEqualMatcher.spec.ts | 4 ++-- test/mocking.types.spec.ts | 2 +- test/recording.multiple.behaviors.spec.ts | 4 ++-- test/stubbing.method.spec.ts | 4 ++-- test/utils/Foo.ts | 4 ++-- tsconfig.json | 1 + 16 files changed, 45 insertions(+), 36 deletions(-) diff --git a/src/MethodStubCollection.ts b/src/MethodStubCollection.ts index 3f8aa6f..54999d3 100644 --- a/src/MethodStubCollection.ts +++ b/src/MethodStubCollection.ts @@ -13,7 +13,7 @@ export class MethodStubCollection { return matchingGroup ? matchingGroup.getGroupIndex() : -1; } - public getFirstMatchingFromGroupAndRemoveIfNotLast(groupIndex: number, args: any[]): MethodStub { + public getFirstMatchingFromGroupAndRemoveIfNotLast(groupIndex: number, args: any[]): MethodStub | null { const result = this.getFirstMatchingFromGroup(groupIndex, args); this.removeIfNotLast(groupIndex, args); return result; @@ -30,8 +30,8 @@ export class MethodStubCollection { } } - private getFirstMatchingFromGroup(groupIndex: number, args: any[]): MethodStub { - return this.items.find((item: MethodStub) => item.getGroupIndex() === groupIndex && item.isApplicable(args)); + private getFirstMatchingFromGroup(groupIndex: number, args: any[]): MethodStub | null { + return this.items.find((item: MethodStub) => item.getGroupIndex() === groupIndex && item.isApplicable(args)) ?? null; } private getFirstMatchingIndexFromGroup(groupIndex: number, args: any[]): number { diff --git a/src/MethodStubSetter.ts b/src/MethodStubSetter.ts index 9b0df50..845639b 100644 --- a/src/MethodStubSetter.ts +++ b/src/MethodStubSetter.ts @@ -35,7 +35,7 @@ export class MethodStubSetter { return this; } - public thenResolve(...rest: ResolveType[]): this { + public thenResolve(...rest: (ResolveType | undefined)[]): this { this.convertToPropertyIfIsNotAFunction(); // Resolves undefined if no resolve values are given. if (rest.length === 0) { diff --git a/src/Mock.ts b/src/Mock.ts index ee83e6a..875c004 100644 --- a/src/Mock.ts +++ b/src/Mock.ts @@ -125,11 +125,11 @@ export class Mocker { return; } const descriptor = Object.getOwnPropertyDescriptor(obj, name); - if (descriptor.get) { + if (descriptor?.get) { this.createPropertyStub(name); this.createInstancePropertyDescriptorListener(name, descriptor, obj); this.createInstanceActionListener(name, obj); - } else if (typeof descriptor.value === "function") { + } else if (typeof descriptor?.value === "function") { this.createMethodStub(name); this.createInstanceActionListener(name, obj); } else { @@ -164,8 +164,8 @@ export class Mocker { const action: MethodAction = new MethodAction(key, args); this.methodActions.push(action); const methodStub = this.getMethodStub(key, args); - methodStub.execute(args); - return methodStub.getValue(); + methodStub?.execute(args); + return methodStub?.getValue(); }; } @@ -225,7 +225,7 @@ export class Mocker { }; } - private getMethodStub(key: string, args: any[]): MethodStub { + private getMethodStub(key: string, args: any[]): MethodStub | null { const methodStub: MethodStubCollection = this.methodStubCollections[key]; if (methodStub && methodStub.hasMatchingInAnyGroup(args)) { const groupIndex = methodStub.getLastMatchingGroupIndex(args); diff --git a/src/Spy.ts b/src/Spy.ts index f23ffd6..8b750f9 100644 --- a/src/Spy.ts +++ b/src/Spy.ts @@ -18,7 +18,7 @@ export class Spy extends Mocker { public reset(): void { _.forEach(this.realMethods, (method, key) => { if (method.instance) { - Object.defineProperty(this.instance, key, method.descriptor); + Object.defineProperty(this.instance, key, method.descriptor ?? {}); } else { delete this.instance[key]; } @@ -31,7 +31,7 @@ export class Spy extends Mocker { const realMethod = this.realMethods[key]; if (realMethod) { - const method = realMethod.descriptor.get || realMethod.descriptor.value; + const method = realMethod.descriptor?.get || realMethod.descriptor?.value; return new CallThroughMethodStub(this.instance, method); } diff --git a/src/matcher/type/DeepEqualMatcher.ts b/src/matcher/type/DeepEqualMatcher.ts index 2fe8afe..9d1f7fb 100644 --- a/src/matcher/type/DeepEqualMatcher.ts +++ b/src/matcher/type/DeepEqualMatcher.ts @@ -8,7 +8,7 @@ export class DeepEqualMatcher extends Matcher { public match(value: any): boolean { return _.isEqualWith(this.expectedValue, value, - (expected: any, actual: any): boolean => { + (expected: any, actual: any) => { if (expected instanceof Matcher) { return expected.match(actual); } diff --git a/src/spy/RealMethod.ts b/src/spy/RealMethod.ts index 8a50af5..d67893e 100644 --- a/src/spy/RealMethod.ts +++ b/src/spy/RealMethod.ts @@ -1,4 +1,4 @@ export class RealMethod { - constructor(public descriptor: PropertyDescriptor, + constructor(public descriptor: PropertyDescriptor | undefined, public instance: boolean) {} } diff --git a/src/tsconfig.json b/src/tsconfig.json index d8725e5..5632d9b 100644 --- a/src/tsconfig.json +++ b/src/tsconfig.json @@ -6,6 +6,7 @@ "target": "es5", "removeComments": true, "sourceMap": true, + "strictNullChecks": true, "declaration": true, "lib": [ "es5", diff --git a/src/utils/MockableFunctionsFinder.ts b/src/utils/MockableFunctionsFinder.ts index 84569c7..77684a0 100644 --- a/src/utils/MockableFunctionsFinder.ts +++ b/src/utils/MockableFunctionsFinder.ts @@ -24,7 +24,7 @@ const methodTokenName = new Set([ const isFunctionNode = (node: _babel_types.Statement | FunctionNode): node is FunctionNode => methodTokenName.has(node.type); -function getAssignmentName(node: _babel_types.LVal) { +function getAssignmentName(node: _babel_types.LVal): string | null { if (node.type === "Identifier") return node.name; @@ -38,28 +38,30 @@ function getAssignmentName(node: _babel_types.LVal) { return null; } -function handleClassProp(node: _babel_types.ClassProperty): string { - if (node.value.type !== 'ArrowFunctionExpression' && node.value.type !== 'FunctionExpression') return null; +function handleClassProp(node: _babel_types.ClassProperty): string | null { + 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 { +function handleExpression(node: _babel_types.Expression): string | null { if ('expression' in node && typeof node.expression !== 'boolean') return handleExpression(node.expression); if (node.type === 'AssignmentExpression') { return getAssignmentName(node.left); } + + return null; } 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; + if (n.init?.type === 'ArrowFunctionExpression') return true; + if (n.init?.type === 'FunctionExpression') return true; return false; - }).map(n => getAssignmentName(n.id)); + }).map(n => getAssignmentName(n.id)).filter(Boolean) as string[]; } function extractFunctionNames(nodes: (_babel_types.Statement | FunctionNode)[]) { @@ -79,7 +81,8 @@ function extractFunctionNames(nodes: (_babel_types.Statement | FunctionNode)[]) } if (node.type === "ExpressionStatement") { - names = [handleExpression(node.expression), ...names]; + const name = handleExpression(node.expression); + if (name) names.push(name) } if (node.type === "VariableDeclaration") { @@ -87,7 +90,10 @@ function extractFunctionNames(nodes: (_babel_types.Statement | FunctionNode)[]) } if (node.type === "ClassProperty") { - names = [handleClassProp(node), ...extractFunctionNames([node.value]), ...names]; + const propName = handleClassProp(node); + const funcNames = node.value ? extractFunctionNames([node.value]) : []; + if (propName) names.push(propName); + names = [...funcNames, ...names]; } }); diff --git a/src/utils/ObjectPropertyCodeRetriever.ts b/src/utils/ObjectPropertyCodeRetriever.ts index 4792fda..7e02965 100644 --- a/src/utils/ObjectPropertyCodeRetriever.ts +++ b/src/utils/ObjectPropertyCodeRetriever.ts @@ -6,17 +6,17 @@ export class ObjectPropertyCodeRetriever { ${props.map(prop => { let result = ''; const descriptor = Object.getOwnPropertyDescriptor(object, prop); - if (descriptor.get) { + if (descriptor?.get) { result += ` - ${descriptor.get.toString()} + ${descriptor?.get.toString()} `; } - if (descriptor.set) { + if (descriptor?.set) { result += ` - ${descriptor.set.toString()} + ${descriptor?.set.toString()} `; } - if (!descriptor.get && !descriptor.set && typeof object[prop] === 'function') { + if (!descriptor?.get && !descriptor?.set && typeof object[prop] === 'function') { const propName = prop === 'constructor' ? 'mock_constructor' : ''; const fnStr = String(object[prop]); result += ` diff --git a/test/matcher/type/AnyOfClassMatcher.spec.ts b/test/matcher/type/AnyOfClassMatcher.spec.ts index d7755a6..8418c41 100644 --- a/test/matcher/type/AnyOfClassMatcher.spec.ts +++ b/test/matcher/type/AnyOfClassMatcher.spec.ts @@ -39,6 +39,7 @@ describe("AnyOfClassMatcher", () => { describe("checking if null matches null", () => { it("throws error", () => { try { + // @ts-ignore force type for test purposes anyOfClass(null); fail("If you reach this statement, the test failed."); } catch (e) { diff --git a/test/matcher/type/DeepEqualMatcher.spec.ts b/test/matcher/type/DeepEqualMatcher.spec.ts index c7438e2..440c437 100644 --- a/test/matcher/type/DeepEqualMatcher.spec.ts +++ b/test/matcher/type/DeepEqualMatcher.spec.ts @@ -128,7 +128,7 @@ describe("deepEqual", () => { describe("using in verify statements", () => { it("can be used for equality", () => { class Foo { - public add = (str: string, num: number, obj: {a: string}): number => null; + public add = (str: string, num: number, obj: {a: string}): number | null => null; } const foo = mock(Foo); instance(foo).add("1", 2, {a: "sampleValue"}); @@ -138,7 +138,7 @@ describe("deepEqual", () => { describe('when given circular dependency', () => { type Bar = { bar?: Bar; }; class Foo { - public something = (bar: Bar): number => null; + public something = (bar: Bar): number | null => null; } it('should reject gracefully', async () => { diff --git a/test/mocking.types.spec.ts b/test/mocking.types.spec.ts index 931e849..b5c4189 100644 --- a/test/mocking.types.spec.ts +++ b/test/mocking.types.spec.ts @@ -288,6 +288,6 @@ class SampleGeneric { } public getGenericTypedValue(): T { - return null; + return null as unknown as T; } } diff --git a/test/recording.multiple.behaviors.spec.ts b/test/recording.multiple.behaviors.spec.ts index e3f15e6..756eb4d 100644 --- a/test/recording.multiple.behaviors.spec.ts +++ b/test/recording.multiple.behaviors.spec.ts @@ -117,7 +117,7 @@ describe("recording multiple behaviors", () => { // when const firstCallResult = foo.convertNumberToString(sampleValue); - let error: Error; + let error: Error | null = null; try { foo.convertNumberToString(sampleValue); } catch (e) { @@ -129,7 +129,7 @@ describe("recording multiple behaviors", () => { // then expect(firstCallResult).toEqual(firstMatchingStubResult); - expect(error.message).toEqual(firstMatchingError.message); + expect(error?.message).toEqual(firstMatchingError.message); expect(thirdCallResult).toEqual(secondMatchingStubResult); expect(fourthCallResult).toEqual(secondMatchingStubResult); expect(fifthCallResult).toEqual(secondMatchingStubResult); diff --git a/test/stubbing.method.spec.ts b/test/stubbing.method.spec.ts index 038ad59..9a04bdf 100644 --- a/test/stubbing.method.spec.ts +++ b/test/stubbing.method.spec.ts @@ -146,7 +146,7 @@ describe("mocking", () => { when(mockedFoo.convertNumberToString(sampleValue)).thenThrow(sampleError); // when - let error = null; + let error:Error | null = null; try { foo.convertNumberToString(sampleValue); } catch (e) { @@ -154,7 +154,7 @@ describe("mocking", () => { } // then - expect(error.message).toEqual("sampleError"); + expect(error?.message).toEqual("sampleError"); }); }); diff --git a/test/utils/Foo.ts b/test/utils/Foo.ts index 27a4454..b688544 100644 --- a/test/utils/Foo.ts +++ b/test/utils/Foo.ts @@ -28,11 +28,11 @@ export class Foo { } public sampleMethodWithOptionalArgument(a: number, b?: number): number { - return a + b; + return a + (b ?? 0); } public sampleMethodWithTwoOptionalArguments(a?: number, b?: number): number { - return a + b; + return (a ?? 0) + (b ?? 0); } public sampleMethodReturningPromise(value: string): Promise { diff --git a/tsconfig.json b/tsconfig.json index d14d15d..a622586 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -7,6 +7,7 @@ "removeComments": true, "sourceMap": true, "declaration": true, + "strictNullChecks": true, "lib": [ "es5", "es6", From 0241a9e7a0817e973947feddf409fbe35d1e7b73 Mon Sep 17 00:00:00 2001 From: rezoled Date: Mon, 15 Jul 2024 11:24:03 +0300 Subject: [PATCH 5/5] strict null checks --- src/utils/MockableFunctionsFinder.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/MockableFunctionsFinder.ts b/src/utils/MockableFunctionsFinder.ts index 77684a0..c46316d 100644 --- a/src/utils/MockableFunctionsFinder.ts +++ b/src/utils/MockableFunctionsFinder.ts @@ -82,7 +82,7 @@ function extractFunctionNames(nodes: (_babel_types.Statement | FunctionNode)[]) if (node.type === "ExpressionStatement") { const name = handleExpression(node.expression); - if (name) names.push(name) + if (name) names.push(name); } if (node.type === "VariableDeclaration") {