From b6518e933bb41fb9e0dcb81894351a21935a1cce Mon Sep 17 00:00:00 2001 From: Rohan Date: Thu, 28 Jun 2018 11:09:01 +1200 Subject: [PATCH] support mocking native async methods when targeting es2017 --- package.json | 7 ++- src/utils/MockableFunctionsFinder.ts | 3 +- test/mocking.types.spec.ts | 61 +++++++++++++++++++ test/utils/MockableFunctionsFinder.spec.ts | 9 +++ .../utils/ObjectPropertyCodeRetriever.spec.ts | 2 +- tsconfig.test.json | 9 +++ 6 files changed, 88 insertions(+), 3 deletions(-) create mode 100644 tsconfig.test.json diff --git a/package.json b/package.json index b6674d6..c9fdf2c 100644 --- a/package.json +++ b/package.json @@ -56,9 +56,14 @@ "lodash": "^4.17.5" }, "jest": { + "globals": { + "ts-jest": { + "tsConfigFile": "tsconfig.test.json" + } + }, "testEnvironment": "jsdom", "transform": { - "^.+\\.ts$": "/node_modules/ts-jest/preprocessor.js" + "^.+\\.ts$": "ts-jest" }, "testRegex": "(/__tests__/.*|\\.(spec))\\.(ts|js)$", "moduleFileExtensions": [ diff --git a/src/utils/MockableFunctionsFinder.ts b/src/utils/MockableFunctionsFinder.ts index 600b1cd..a7bef46 100644 --- a/src/utils/MockableFunctionsFinder.ts +++ b/src/utils/MockableFunctionsFinder.ts @@ -7,9 +7,10 @@ * - [.]functionName = ( * - [.]functionName = function( * - [.]functionName = function otherName( + * - [.]functionName = async . */ export class MockableFunctionsFinder { - private functionNameRegex = /[.\s]([^.\s]+?)(?:\(|\s+=\s+(?:function\s*(?:[^.\s]+?\s*)?)?\()/g; + private functionNameRegex = /[.\s]([^.\s]+?)(?:\(|\s+=\s+(?:function\s*(?:[^.\s]+?\s*)?)?\(|\s+=\s+async\s)/g; private cleanFunctionNameRegex = /^[.\s]([^.\s]+?)[\s(]/; private excludedFunctionNames: string[] = ["hasOwnProperty", "function"]; diff --git a/test/mocking.types.spec.ts b/test/mocking.types.spec.ts index cfd86df..8173289 100644 --- a/test/mocking.types.spec.ts +++ b/test/mocking.types.spec.ts @@ -152,6 +152,57 @@ describe("mocking", () => { }); }); + + describe("mocking class with async methods", () => { + let mockedFoo: SampleClassWithAsync; + let foo: SampleClassWithAsync; + + it("does create own method descriptors on instance 0", () => { + // given + mockedFoo = mock(SampleClassWithAsync); + foo = instance(mockedFoo); + + // when + when(mockedFoo.asyncMethod0()).thenResolve(42); + + // then + return foo.asyncMethod0() + .then(result => { + expect(result).toBe(42); + }); + }); + + it("does create own method descriptors on instance 1", () => { + // given + mockedFoo = mock(SampleClassWithAsync); + foo = instance(mockedFoo); + + // when + when(mockedFoo.asyncMethod1('bar')).thenResolve(42); + + // then + return foo.asyncMethod1('bar') + .then(result => { + expect(result).toBe(42); + }); + }); + + it("does create own method descriptors on instance 2", () => { + // given + mockedFoo = mock(SampleClassWithAsync); + foo = instance(mockedFoo); + + // when + when(mockedFoo.asyncMethod2('bar', 2)).thenResolve(42); + + // then + return foo.asyncMethod2('bar', 2) + .then(result => { + expect(result).toBe(42); + }); + }); +}); + }); abstract class SampleAbstractClass { @@ -211,3 +262,13 @@ class SampleGeneric { return null; } } + +class SampleClassWithAsync { + + protected constructor() {} + + // because the compiler produces different signatures for each of these + public asyncMethod0 = async () => 4; + public asyncMethod1 = async (foo: string) => Number(foo); + public asyncMethod2 = async (foo: string, bar: number) => bar; +} diff --git a/test/utils/MockableFunctionsFinder.spec.ts b/test/utils/MockableFunctionsFinder.spec.ts index 894d0f7..c8e2089 100644 --- a/test/utils/MockableFunctionsFinder.spec.ts +++ b/test/utils/MockableFunctionsFinder.spec.ts @@ -13,6 +13,8 @@ describe("MockableFunctionsFinder", () => { expect(result).toContain("log"); expect(result).toContain("toString"); expect(result).toContain("anonymousMethod"); + expect(result).toContain("asyncMethod1"); + expect(result).toContain("asyncMethod2"); }); it("should not find hasOwnProperty as it should not be mocked (because its used by mockito to evaluate properties)", () => { @@ -36,6 +38,13 @@ export class Foo { console.log(arg); temp.hasOwnProperty("fakeProperty"); } + + this.asyncMethod1 = async arg => { + } + + this.asyncMethod2 = async (foo, bar) => { + } + } private convertNumberToString(value:number):string { diff --git a/test/utils/ObjectPropertyCodeRetriever.spec.ts b/test/utils/ObjectPropertyCodeRetriever.spec.ts index 139c23c..b3c5f58 100644 --- a/test/utils/ObjectPropertyCodeRetriever.spec.ts +++ b/test/utils/ObjectPropertyCodeRetriever.spec.ts @@ -28,7 +28,7 @@ describe("ObjectPropertyCodeRetriever", () => { 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 \(\)/); + expect(objectPropertyCodeRetriever.get(object, "testMethod")).toMatch(/() => true/); }); it("Provides code of given existing property accessors", () => { diff --git a/tsconfig.test.json b/tsconfig.test.json new file mode 100644 index 0000000..12b3ac4 --- /dev/null +++ b/tsconfig.test.json @@ -0,0 +1,9 @@ +{ + "extends": "./tsconfig", + "compilerOptions": { + "target": "es2017", + "lib": [ + "es2017" + ] + } +}