Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jest unit-testing if super() is called

I have a custom error class that extends the built-in Error class in Javascript. The problem I came up with is that "super()" method is not checked if it is called or not through my Jest unit testing.

export class AppError extends Error {
  public name: string;
  public message: string;
  public status?: number;
  public data?: any;
  constructor(message: string, status?: number, data?: any) {
    super(); <-- this guy!!
    this.name = 'AppError';
    this.status = status || 500;
    this.message = message;
    this.data = data;
  }
}

Is there any way to test it? Thanks.

like image 954
supergentle Avatar asked Jul 06 '18 18:07

supergentle


1 Answers

There's no reason to check if super() is called neither in native ES6 classes nor in classes transpiled with Babel.

Not calling super in child class constructor will result in error on class instantiation:

ReferenceError: Must call super constructor in derived class before accessing 'this' or returning from derived constructor

Babel provides a safeguard for that as well:

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

It may be possible to check that parent constructor is called (could be useful to assert super() arguments) by mocking child class prototype, something like:

let ParentOriginal;
let ParentMock;

beforeEach(() => {
  ParentOriginal = Object.getPrototypeOf(AppError);
  ParentMock = jest.fn();
  Object.setPrototypeOf(AppError, ParentMock);
});

it('..', () => {
  new AppError(...);
  expect(ParentMock.mock.calls.length).toBe(1);
})

afterEach(() => {
  Object.setPrototypeOf(AppError, ParentOriginal);
});

It's expected to mock super in both native classes and classes transpiled with Babel.

But this test is redundant, because missing super() will result in error any way. Testing that AppError inherits from Error is everything that needs be tested here:

expect(new AppError(...)).toBeInstanceOf(Error)
like image 117
Estus Flask Avatar answered Oct 24 '22 04:10

Estus Flask