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

Proxy created with instance(mockedClass) gets "then" function -> Results in Timeout when Using Nestjs DI #219

Open
ChrisWun opened this issue Aug 13, 2021 · 2 comments

Comments

@ChrisWun
Copy link

I use ts-mockito to test my NestJs application. Basically it works very well, but there are problems if the word "then" is somewhere in the code. If the word "then" is present, the created proxy object is assigned a function "then". When using NestJs with Jest, this leads to a timeout when using the mock by overriding a provider for dependency injection.

export class Foo {
  myFunction(): Promise<string> {
    return Promise.resolve().then(() => {
      return 'foo';
    });
  }
}
const mockedFoo = mock(Foo);
const foo = instance(mockedFoo);

Results in:
Bildschirmfoto 2021-08-13 um 07 56 47

It is also very strange that the Promise functions (then, resolve) are also added as a function on the proxy when the corresponding code has been commented out, but is inside a block of a function!

export class Foo {
  myFunction(): Promise<string> {
    return Promise.resolve('foo');
    // return Promise.resolve().then(() => {
    //   return 'foo';
    // });
  }
}
const mockedFoo = mock(Foo);
const foo = instance(mockedFoo);

Results in:
Bildschirmfoto 2021-08-13 um 07 56 47

As a workaround to be able to use the mocks with NestJs Dependency Injection, I remove the then property from the proxy:
delete foo['then']

@RageCage64
Copy link

This issue was also discovered around a year ago in #191 with an open PR to fix #194. The fix appears to work exactly as expected. I hope that it can be merged soon.

@dariosn85
Copy link

We had the same problem. I was not aware of this ticket before, so I've analyzed everything on my own already before. The cause for the timeout is because NestJS under the hood calls await on resolved DI tokens (object). Since object (mock) contains the then() method it is considered as a promise and await call wait on it to be resolved, but this never happens.

Why mocked object has .then() method even, if this method was commented out from your code? Because Mocker calls .toString() on a class to determine which methods it should mock. This class string is then parsed by regex in MockableFunctionsFinder and as an output we have also .then().

One possible workaround is what you already mention: deleting .then() after mock is created. If you would like to solve this more generic without waiting ts-mockito fix and calling delete in every test, you coul monkey patch MockableFunctionsFinder via jest.setup.ts or similar. See following code that we used:

export class TestUtil {
    public static patchTsMockito(): void {
        try {
            const MockableFunctionsFinder = require('ts-mockito/lib/utils/MockableFunctionsFinder').MockableFunctionsFinder;
            if (!MockableFunctionsFinder.prototype.isMockableOriginal) {
                MockableFunctionsFinder.prototype.isMockableOriginal = MockableFunctionsFinder.prototype.isMockable;

                MockableFunctionsFinder.prototype.isMockable = function (name: string): boolean {
                    if (['catch', 'then'].indexOf(name) >= 0) {
                        return false;
                    }

                    return this.isMockableOriginal(name);
                };
            }
        } catch (error) {
            console.warn('Failed to patch ts-mockito MockableFunctionsFinder', error);
        }
    }
}

By this fix .then() and .catch() methods are ignored - false is returned by isMockable() call. You can then simply call this patch method within jest.setup.ts like:

TestUtil.patchTsMockito()

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