Jest Recap: Access `private` Members in TypeScript Unit Tests

htho

Hauke T.

Posted on September 14, 2022

Jest Recap: Access `private` Members in TypeScript Unit Tests

TL;DR: Use bracket notation to Access private properties

expect(inst["_somePrivateProp"]).toBe("foo"); // OK
Enter fullscreen mode Exit fullscreen mode

Disclaimer

This is not a lengthy discussion. But a small reference type post. There are other (lengthy) posts that go into the details. I like it short.

Introduction

There is some ongoing debate about testing private members (methods, fields, properties, ...). In my opinion there are occasions where it is useful to do that.

It is not possible to directly inspect/test private members in languages like C#. But there is a common inheritance based workround, where private members are made protected.

In your test code you extend those classes and write wrappers/accessors to access these members. Then you actually test your derived class.

This is cumbersome and also changes the semantics of the class you want to test. private members appear to be intended to be accessed in derived classes. Which is not the case!


JavaScript/TypeScript

JavaScript/TypeScript does not require you to do that (at least for TypeScript private members, not for ES private (#) class fields).

// mod.ts
export class SomeClass {
    private _somePrivateProp = "foo";
}
Enter fullscreen mode Exit fullscreen mode

JavaScript does not care if your member is marked private by TypeScript.
The TypeScript compiler enforces that you don't access private members from outside the class using dot notation (inst.prop).
But it is possible to access the property using bracket notation (inst["prop"]).

// mod.test.ts
import {SomeClass} from "./mod.ts";
test("privatePropIsFoo", () => {
    const inst = new SomeClass();
    expect(inst._somePrivateProp).toBe("foo"); // TS2341: Property '_somePrivateProp' is private and only accessible within class 'SomeClass'.

    expect(inst["_somePrivateProp"]).toBe("foo"); // OK
})
Enter fullscreen mode Exit fullscreen mode

This is great because refactoring tools still work. And it saves a lot of redundant code.

A caveat

jest.spy(inst, "_privateMethod") will not work, because TypeScript enforces that only public methods are spied on. The simplest workaround is to cast inst as any. Until there is a Utility Type that treats all members as public (as already suggested).

💖 💪 🙅 🚩
htho
Hauke T.

Posted on September 14, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related