Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Passing Dynamic Mock to Promise Resolve #66

Closed
jdbriaris opened this issue May 28, 2017 · 3 comments
Closed

Passing Dynamic Mock to Promise Resolve #66

jdbriaris opened this issue May 28, 2017 · 3 comments

Comments

@jdbriaris
Copy link

I've defined MyService as follows

export interface MyService {
    doStuff(): Promise<any>;
}

and MyClass that consumes MyService as

import {MyService} from "./my.service";
import {Observable} from "rxjs/Observable";
export class MyClass {

    constructor(private myService: MyService) {}

    useMyService(): Observable<boolean> {
        return Observable.create(obs => {
            this.myService.doStuff()
                .then((res: any) => {
                    console.log("Promise resolved!");
                    obs.next(true);
                })
                .catch((err: any) => {
                    console.log("Promise rejected!");
                    obs.error(false);
                })
        });
    };    
}

In addition, I have an interface MyModel defined as

export interface MyModel {
    someProperty: string;
}

Now I want to write a test such that I can mock MyService using TypeMoq. So I did the following

describe('MyClass', () => {

    it('useMyService returns true when myService returns true', (done) => {
        let mockModel = TypeMoq.Mock.ofType<MyModel>();
        mockModel.setup(x => x.someProperty).returns(() => "info");    

        let mockMyService = TypeMoq.Mock.ofType<MyService>();
        mockMyService.setup(x => x.doStuff()).returns(() => Promise.resolve(mockModel.object));

        let myClass = new MyClass(mockMyService.object);

        myClass.useMyService().subscribe(
            (result: boolean) => {
                expect(result).toBeTruthy();
                done();
            },
            (error: any) => {
                expect(error).toBeFalsy();
                done();
            });
    });
});

However, the Promise.resolve(mockModel.object) never seems to resolve when supplied with the TypeMoq mock as shown above, i.e., I don't get "Promise resolved!" (or "Promise rejected!") printed to the console and the jasmine test times out.

If I replace Promise.resolve(mockModel.object) with Promise.resolve({ someProperty: 'info'}), i.e.,

let mockMyService = TypeMoq.Mock.ofType<MyService>();
        mockMyService.setup(x => x.doStuff()).returns(() => Promise.resolve({ someProperty: 'info'}));

then the test works (I get "Promise resolved!" printed to the console). Why doesn't Promise.resolve() resolve when supplied with a TypeMoq mock? Is this a limitation of dynamic mocking?

@florinn
Copy link
Owner

florinn commented Jun 23, 2017

Passing a mock object to Promise.resolve doesn't seem to make much sense.

I assume your intention was to resolve it like this:

...
mockMyService.setup(x => x.doStuff()).returns(() => Promise.resolve(mockModel.object.someProperty));
...

Let me know if your test still fails after making the change above.

@ron-macneil-youi
Copy link

Hi @florinn,

Can you explain why mocks yielding Promises to other mocks (as @jdbriaris illustrates above) "doesn't make much sense"?

It seems a perfectly reasonable scenario to me -- indeed our team requires it -- and it is still broken in master per this slight modification to the should return a Promise resolved with a mocked property test.

Regards,
Ron

--- a/test/spec/Mock.test.ts
+++ b/test/spec/Mock.test.ts
@@ -1401,7 +1401,7 @@ describe("Mock", () => {
                     mockModel.setup(x => x.someProperty).returns(() => "info");

                     const mockMyService = TypeMoq.Mock.ofType<MyService>();
-                    mockMyService.setup(x => x.doStuff()).returns(() => Promise.resolve(mockModel.object.someProperty))
+                    mockMyService.setup(x => x.doStuff()).returns(() => Promise.resolve(mockModel.object));

                     const myClass = new MyClass(mockMyService.object);

@florinn
Copy link
Owner

florinn commented Jul 17, 2017

Hi @ron-macneil-youi

If your test scenario requires passing a mock object to Promise.resolve then you have to make sure the mock object is thenable by adding a .then setup:

let mockModel = TypeMoq.Mock.ofType<MyModel>();
mockModel.setup((x: any) => x.then).returns(() => undefined);
...

This is due to a limitation of the underlying technology. For more information see issue #70

shousper pushed a commit to shousper/typemoq that referenced this issue Jul 26, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants