Search code examples
sinonstronglooploopback4

Loopback 4: Test problems with Sinon and injections


We have trying to do a test with loopback. The test involve to call the google API and we want to mock it with Sinon.

The Controller:

[...]

In the constructor:

  @inject('services.OAuth2Service')
    private oauth2Service: OAuth2Service

[...]

In the endpoint:

@post('/user-accounts/authenticate/oauth2', {
async authenticateOauth2(
    @requestBody() oauthRequest: OAuthId,
    @inject(RestBindings.Http.REQUEST) _req: Request,
  ): Promise<AccessToken> {
    const email = await this.oauth2Service.getOAuth2User(oauthRequest); // The method to mock.
  ....
}

The test:

it('oauth2 authentication with google', async () => {

 //Create a spy for the getOAuth2User function
    inject.getter('services.OAuth2Service');
    var oauth2Service: OAuth2Service;

    var setOauthSpy = sinon.spy(oauth2Service, "getOAuth2User"); // Error: Variable 'oauth2Service' is used before being assigned

    const res = await client
      .post('/user-accounts/authenticate/oauth2')
      .set('urlTenant', TEST_TENANT_URL1A)
      .set('userType', TEST_USERTYPE1)
      .send({
        code: TEST_GOOGLE_AUTH2_CODE_KO,
        providerId: TEST_GOOGLE_PROVIDER,
        redirectUri: TEST_GOOGLE_REDIRECT_URI,
      })
      .expect(401);
    expect(res.body.error.message).to.equal('The credentials are not correct.');

    setOauthSpy.restore();

  });

How can we test this method? how can we test an endpoint who involves an injection in the constructor in loopback? Please, we need any help.


Solution

  • I see two options:

    1. Before running the test, create a loopback context, bind your stub to "services.OAuth2Service" and use that context to create the controller you want to test.

    2. default value (probably not what you want)

    In the place where you use @inject, you provide a default value (and possibly indicate the dependency is optional), e.g. like this:

    @inject('services.OAuth2Service', { optional: true })
        private oauth2Service: OAuth2Service = mockOAuth2Service,
    

    In other places this might come handy for you, but you should probably not pollute your default production code with defaults to test objects.