diff --git a/src/Mock.ts b/src/Mock.ts index 3c98f72..8d6c500 100644 --- a/src/Mock.ts +++ b/src/Mock.ts @@ -18,6 +18,7 @@ export class Mocker { private mockableFunctionsFinder = new MockableFunctionsFinder(); private objectPropertyCodeRetriever = new ObjectPropertyCodeRetriever(); private excludedPropertyNames: string[] = ["hasOwnProperty"]; + private defaultedPropertyNames: string[] = ["Symbol(Symbol.toPrimitive)", "then", "catch"]; constructor(private clazz: any, public instance: any = {}) { this.mock.__tsmockitoInstance = this.instance; @@ -39,6 +40,9 @@ export class Mocker { const hasMethodStub = name in target; if (!hasMethodStub) { + if (this.defaultedPropertyNames.indexOf(name.toString()) >= 0) { + return undefined; + } return this.createActionListener(name.toString()); } return target[name]; @@ -77,6 +81,9 @@ export class Mocker { get: (target: any, name: PropertyKey) => { const hasMethodStub = name in target; if (!hasMethodStub) { + if (this.defaultedPropertyNames.indexOf(name.toString()) >= 0) { + return undefined; + } this.createPropertyStub(name.toString()); this.createInstancePropertyDescriptorListener(name.toString(), {}, this.clazz.prototype); } diff --git a/test/interface.spec.ts b/test/interface.spec.ts index b1e4a3f..e5fdb67 100644 --- a/test/interface.spec.ts +++ b/test/interface.spec.ts @@ -1,26 +1,73 @@ import { instance, mock, when } from "../src/ts-mockito"; import { FooInterface } from "./utils/FooInterface"; +import { ThenableInterface } from "./utils/Thenable"; describe("Interface", () => { - let mockedFoo: FooInterface; - let foo: FooInterface; - if (typeof Proxy === "undefined") { pending("Testing browser doesn't support Proxy."); } - beforeEach(() => { - mockedFoo = mock(); - foo = instance(mockedFoo); + describe("Basic", () => { + let mockedFoo: FooInterface; + let foo: FooInterface; + + beforeEach(() => { + mockedFoo = mock(); + foo = instance(mockedFoo); + }); + + it("should mock interface function", () => { + // Rest cases for interfaces are tested in verification.spec.ts + + // when + when(mockedFoo.sumByInterface(2, 3)).thenReturn(1000); + + // then + expect(foo.sumByInterface(2, 3)).toEqual(1000); + }); }); + describe("Promise", () => { + let mockedThen: ThenableInterface; + let inst: ThenableInterface; + + beforeEach(() => { + mockedThen = mock(); + inst = instance(mockedThen); + }); + + it("does not create then descriptor for interface", () => { + // given + + // when + + // then + expect(inst.then).toBeUndefined(); + }); + it("creates then descriptor for interface", () => { + // given + + // when + when(mockedThen.then()).thenReturn("woof"); + + // then + expect(inst.then).toBeDefined(); + }); + it("does not create catch descriptor for interface", () => { + // given + + // when - it("should mock interface function", () => { - // Rest cases for interfaces are tested in verification.spec.ts + // then + expect(inst.catch).toBeUndefined(); + }); + it("creates catch descriptor for interface", () => { + // given - // when - when(mockedFoo.sumByInterface(2, 3)).thenReturn(1000); + // when + when(mockedThen.catch()).thenReturn("woof"); - // then - expect(foo.sumByInterface(2, 3)).toEqual(1000); + // then + expect(inst.catch).toBeDefined(); + }); }); }); diff --git a/test/mocking.types.spec.ts b/test/mocking.types.spec.ts index ecae9c5..b7a8c62 100644 --- a/test/mocking.types.spec.ts +++ b/test/mocking.types.spec.ts @@ -1,6 +1,7 @@ -import {MethodToStub} from "../src/MethodToStub"; -import {instance, mock, when} from "../src/ts-mockito"; -import {Bar} from "./utils/Bar"; +import { MethodToStub } from "../src/MethodToStub"; +import { instance, mock, when } from "../src/ts-mockito"; +import { Bar } from "./utils/Bar"; +import { ThenableClass } from "./utils/Thenable"; describe("mocking", () => { describe("mocking abstract class", () => { @@ -63,6 +64,65 @@ describe("mocking", () => { expect(foo.sampleString).toBe("42"); }); }); + describe("mocking promise methods", () => { + it("does not create then descriptor for class", () => { + // given + const mocked = mock(SampleAbstractClass); + const inst = instance(mocked); + + // when + + // then + expect((inst as any).then).toBeUndefined(); + }); + + it("does create then descriptor", () => { + // given + const mocked = mock(ThenableClass); + const inst = instance(mocked); + + // when + when(mocked.then()).thenReturn("42"); + + // then + expect(inst.then()).toEqual("42"); + }); + + it("does not create catch descriptor", () => { + // given + const mocked = mock(SampleAbstractClass); + const inst = instance(mocked); + + // when + + // then + expect((inst as any).catch).toBeUndefined(); + }); + + it("does create catch descriptor", () => { + // given + const mocked = mock(ThenableClass); + const inst = instance(mocked); + + // when + when(mocked.catch()).thenReturn("42"); + + // then + expect(inst.catch()).toEqual("42"); + }); + + it("default object formatting works", () => { + // given + const mocked = mock(ThenableClass); + const inst = instance(mocked); + + // when + + // then + const str = `"${inst}"`; + expect(str).toEqual('"[object Object]"'); + }); + }); describe("mocking class with hasOwnProperty", () => { let mockedFoo: SampleClassWithHasOwnProperty; diff --git a/test/utils/Thenable.ts b/test/utils/Thenable.ts new file mode 100644 index 0000000..7a3ed47 --- /dev/null +++ b/test/utils/Thenable.ts @@ -0,0 +1,15 @@ +export abstract class ThenableClass { + public then(): string { + return "bob"; + } + + public catch(): string { + return "bob"; + } +} + +export interface ThenableInterface { + then(): string; + + catch(): string; +}