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

How to mock async functions? #92

Closed
bahrmichael opened this issue Mar 11, 2018 · 2 comments
Closed

How to mock async functions? #92

bahrmichael opened this issue Mar 11, 2018 · 2 comments

Comments

@bahrmichael
Copy link

bahrmichael commented Mar 11, 2018

I have issues with mocking an async function. I assume that I can return a promise when the mocked method is called, so that the then function can be called on that promise. However when running the test, I get the following error:

  1) LoginSpec
       login should return a valid app token:
     TypeError: Cannot read property 'then' of null
      at Promise (src/login.js:1:11787)
      at new Promise (<anonymous>)
      at LoginService.getToken (src/login.js:1:11319)
      at LoginService.<anonymous> (src/login.js:1:9410)
      ...

Test class:

import {expect} from 'chai';
import {suite, test} from "mocha-typescript";
import {anything, instance, mock, when} from "ts-mockito";
import {LoginService} from '../src/login';
import {RestAccess} from "../src/rest";

@suite
class LoginSpec {

    private restMock = mock(RestAccess);

    @test.only
    public async 'login should return a valid app token'() {
        // given
        const ssoToken = {
            access_token: 'AccessToken',
            refresh_token: 'RefreshToken',
        };

        const promise = new Promise((resolve, reject) => {
            resolve(ssoToken);
        });

        when(this.restMock.fetchJson('url', anything))
            .thenReturn(promise);

        const sut = new LoginService(instance(this.restMock));

        // when
        const event = {
            queryStringParameters: {
                code: 'ssoCode',
            },
        };

        const appToken = await sut.login(event);

        // then
        const decodedToken = this.auth.decodeToken(appToken);
        ...
    }
}

Call to mock:

private getToken(code: string): Promise<any> {
        return new Promise((resolve, reject) => {
            const options = {
                ...
            };

            this.rest.fetchJson('url', options).then(result => {
                console.log('resolve');
                resolve(result);
            }).catch(err => {
                reject(err);
            });
        });
    }

Mocked method:

    public async fetchJson(url: string, options: any) {
        const response = await fetch(url, options);
        const data = await response.json();
        return data;
    }

package.json

{
  "dependencies": {
    "@types/jsonwebtoken": "^7.2.5",
    "@types/mysql": "^2.15.3",
    "@types/node-fetch": "^1.6.7",
    "jsonwebtoken": "^8.2.0",
    "mysql": "^2.15.0",
    "node-fetch": "^2.1.1"
  },
  "devDependencies": {
    "@types/aws-lambda": "0.0.33",
    "@types/chai": "^4.1.2",
    "@types/mocha": "^2.2.48",
    "chai": "^4.1.2",
    "eslint": "^4.18.2",
    "eslint-plugin-mocha": "^4.12.1",
    "mocha": "^5.0.4",
    "mocha-typescript": "^1.1.12",
    "nyc": "^11.4.1",
    "serverless-offline": "^3.18.0",
    "serverless-plugin-typescript": "^1.1.5",
    "ts-mockito": "^2.3.0"
  },
  "scripts": {
    "pretest": "tsc",
    "test": "nyc mocha",
    "watch": "mocha-typescript-watch",
    "prepare": "tsc"
  }
}
@NagRock
Copy link
Owner

NagRock commented Mar 12, 2018

Hi @bahrmichael
First of all you can use thenResolve("value") functionality made by @johanblumenberg https://github.com/NagRock/ts-mockito#resolving--rejecting-promises without manually handling promises.

And the line of code I think makes problem in your example is when(this.restMock.fetchJson('url', anything)).thenReturn(promise);

You have forgotten brackets while using anything matcher" anything => anything()

You can change this line to: when(this.restMock.fetchJson('url', anything()).thenResolve(ssoToken)

@bahrmichael
Copy link
Author

anything() did it. JavaScript is not my native language :/ Thank you very much!

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

2 participants