ts-sinon icon indicating copy to clipboard operation
ts-sinon copied to clipboard

stubConstructor does not stub base class methods

Open laleksiunas opened this issue 4 years ago • 6 comments

Steps to reproduce:

  • Have a base class with a method named "foo"
  • Extend the base class and add a method named "bar"
  • Use stubConstructor to stub methods of the latter class

Code sample:

class A {
  foo() {
    return 'a';
  }
}

class B extends A {
  bar() {
    return 'b';
  }
}

const stubbedB = stubConstructor(B);

console.log(stubbedB.bar) // [Function: functionStub]
console.log(stubbedB.foo) // undefined

laleksiunas avatar Nov 06 '20 14:11 laleksiunas

Is there some kind of work around for this? I guess an interface that defines all methods?

Would this be a difficult thing to fix? I may be able to help.

joshystuart avatar Feb 15 '21 05:02 joshystuart

Is there some kind of work around for this? I guess an interface that defines all methods?

Would this be a difficult thing to fix? I may be able to help.

I'm having a similar problem.

I haven't been able to find a way to stub parent methods in a child class. A sample code to demonstrate:

import express from 'express';
class BaseController {
  error(res: express.Response, errorMessage: string, statusCode: number) {
    res.status(statusCode).json(errorMessage)
  }
}

class AuthController extends BaseController {
  constructor() { super() }
  verifyAuthToken(req, res, next) { // normal express.js style for controllers
    const token = getToken() // imagine this was a function that returns some auth token
    if (token === undefined) {
      super.error(res, 'Auth token not provided', 400);
    }
  }
}

I had some code similar to what's above and I wanted to write a test to make sure when the token is undefined, the error method on the parent class will be called. But I could not test that the error method was called:

import { stubObject, stubInterface, stubConstructor } from "ts-sinon";
import { expect } from "chai";

const authServiceStub = stubObject<AuthService>(authService);

describe('AuthService', () => {
  describe('verifyAuthToken method', () => {
      it('should call super.error when no getToken returns undefined', () => {
        
        ....

        authServiceStub.verifyAuthToken(req, res, next)
        expect(authServiceStub.error.callCount).to.be.equal(1)
        expect(authServiceStub.error.calledWith('Auth token not provided')).to.be.true
      })
  })  

When I run the test, I get the following error: TypeError: Cannot read property 'callCount' of undefined

Please I really need help on this! Is there a specific way to create stubs for parent methods of a class?

Emmytobs avatar Jun 30 '21 13:06 Emmytobs

I guess the workaround might be to use stubInterface and manually stub all the methods you need for a specific test, however, this is not ideal.

laleksiunas avatar Jul 03 '21 15:07 laleksiunas

Have the same issue. Any ideas?

AvantaR avatar Sep 08 '21 11:09 AvantaR

@laleksiunas @Emmytobs @joshystuart

I've dug into it a little, and found out that it works when I transform my typescript code to ES5. Everything above that doesn't work. It's connected with Object.getPrototypeOf() and classes in >ES5. Check your tsconfig.json settings, and please confirm if it works for you as well with ES5.

AvantaR avatar Sep 08 '21 15:09 AvantaR

I've created a pull request which should resolve this issue. Please check it -> #251

AvantaR avatar Sep 10 '21 12:09 AvantaR