sinonjs / sinon

Test spies, stubs and mocks for JavaScript.

Home Page:https://sinonjs.org/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Cannot stub private methods in native JavaScript classes

BillyRayPreachersSon opened this issue · comments

Describe the bug
I'm trying to test a native JavaScript class that contains a mix of public and private methods. While I can easily stub the public methods to test them, I'm unable to do so with the private methods.

I've tested against Sinon.JS 9.2.4 in our codebase, as well as against what I believe to be Sinon.JS 17.0.1 (in the console while visiting https://sinonjs.org/), and the behaviour is the same: an error stating "TypeError: Cannot stub non-existent property [name]".

To Reproduce

const MyClass = class {
  aPublicMethod() {
    console.log('public');
  }

   #aPrivateMethod() {
     console.log('private');
   }
}
const myInstance = new MyClass();
  • Try and stub the public method: sinon.stub(myInstance, 'aPublicMethod') - this works fine
  • Try and stub the private method - either with or without the hash prefix: sinon.stub(myInstance, 'aPrivateMethod') or sinon.stub(myInstance, '#aPrivateMethod') - neither work

Expected behaviour
Stubbing private methods would work.

Actual behaviour
I get an error: "TypeError: Cannot stub non-existent property #aPrivateMethod".

Context (please complete the following information):

  • Sinon version : 9.2.4 and 17,.0.1 (see note at top of issue)
  • Runtime: Chrome 121.0.6167.184 (Official Build) (x86_64)

This is not a bug. To quote MDN:

Private properties get created by using a hash # prefix and cannot be legally referenced outside of the class. The privacy encapsulation of these class properties is enforced by JavaScript itself.

Sinon cannot do magic: if the JS engine itself prevents any other object from reaching the property, neither can we. As you can see from the below screenshot, there is no trace of the private field in the MyClass prototype. If it does not have a property for us to manipulate, we cannot reference it, hence the quite correct "Cannot stub non-existent property #aPrivateMethod", as there is no such property.

image

And frankly, that is exactly how it should be. If your unit tests are tampering with privates you should rightly be prevented from accessing them 😄 If you don't want JS to enforce privacy, don't use the feature. You could then use a convention as in the old days of having __privateProperty or something, if you really wish to.