Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

stub readonly property throw "Cannot stub non-existent property" #2266

Closed
ljian3377 opened this issue Jun 5, 2020 · 6 comments
Closed

stub readonly property throw "Cannot stub non-existent property" #2266

ljian3377 opened this issue Jun 5, 2020 · 6 comments

Comments

@ljian3377
Copy link

ljian3377 commented Jun 5, 2020

Describe the bug

  • Library version: 9.0.2

To Reproduce

import * as sinon from "sinon";
class B {
    public readonly a: string;
    public get(): void {}
}

const bStub = sinon.createStubInstance(B);
sinon.stub(bStub , "a").value("test");

// let b = new B();
// sinon.stub(b, "a").value("test");

Expected behavior
stub properly.

There is an old issue mentioning the same issue but is closed with a comment that is not quite helpful for me. #829

@ljian3377
Copy link
Author

However, assigning value beforehand to the property, then the stub will work. But I really don't want to invoke the constructor as it's prettty complicated.

import * as sinon from "sinon";

class B {
    public readonly a: string;
    public get(): void {}
    constructor(aa: string) {
        this.a = aa;
    }
}

// const bStub = sinon.createStubInstance(B);
let b = new B("t");
sinon.stub(b, "a").value("test");
console.log(b.a);

output: test

@ljian3377
Copy link
Author

Currently working around with directly assigning to the stub object.

import * as sinon from "sinon";

class B {
    public readonly a: string;
    public get(): void {}
    constructor(aa: string) {
        this.a = aa;
    }
}

const bStub = sinon.createStubInstance(B);
(bStub as any).a = "test";
console.log(b.a);

output: test

@mroderick
Copy link
Member

We have made conscious decision to not allow stubbing non-existent properties, as that would make for some very confusing scenarios.

The submitted code doesn't look like JavaScript to me, I don't know how to run it.

Please create a new issue and fill in the template to save everyone some time.

@gukoff
Copy link
Contributor

gukoff commented Aug 11, 2023

We have made conscious decision to not allow stubbing non-existent properties, as that would make for some very confusing scenarios.

What are the confusing scenarios?
Would it help to add this functionality behind a flag stub(obj, 'propertyName', forceIfNonExistent=true) to make sure the user knows what they are doing?

@fatso83
Copy link
Contributor

fatso83 commented Aug 11, 2023

@gukoff You can end up spending a lot of time barking up the wrong tree when you stub something that is never supposed to exist. It could be you stubbed the wrong thing, the wrong way or misspelled the property. Better safe than sorry. That is why we would much rather have an explicit call that tells your intent is to define a property that does not currently exist. The API we have talked about looks like sinon.define(obj, prop, fake) (you can read more in that issue about this, might find it interesting from the history), but someone needs to do the (arguably quite minimal) work. That would also go hand-in-hand with sinon.replace*.

The scenario above is about an object mutating itself. The changes are not persistent on any prototype and you do not need to clean it up afterwards. If you choose to construct an object without invoking its constructor, there's no big reason to not do the assignment directly, as he did, as you are already responsible for doing the construction yourself.

@gukoff
Copy link
Contributor

gukoff commented Aug 11, 2023

@fatso83 I see, thanks. Could you take a look if this is someting you're looking for?
#2539

If yes, I could finish this PR next week.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants