timkindberg / jest-when

Jest support for mock argument-matched return values.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Support for expecting / asserting `this` argument

wh1t3cAt1k opened this issue · comments

When I mock one function in MyClass.prototype, I would like to assert and expect that the mock was called with the correct this value (on a particular instance).

AFAIU there is no possibility for that now – but it would be a really nice functionality to have.

Or are there any ways to achieve that in the current version?

Can you provide some code examples? Is this something that you can do with normal Jest assertions?

Sure, this can be done in pure Jest like so:

const myFunctionMock = jest.fn();
MyClass.prototype.myFunction = myFunctionMock; // or jest spy on
const instance = new MyClass();
instance.myFunction();

expect(myFunctionMock.mock.instances[0]).toBe(instance);

But the syntax is somewhat verbose.

Seemingly Jest keeps track of all instances the mocked function was invoked on.

I'm not sure I fully understand what is going on here... wouldn't MyClass have to be a mock and MyClass would have the .mock.instances property? You aren't new-ing up any myFunctionMock instances... why would it have any instances?

I will say that I'd generally like to support most jest mocking behaviors, so if .mock.instances is not working how you'd expect then we should look into it. But I don't really want to add special behaviors or features outside of what a developer familiar with Jest would expect from this library.

Can you show me an example of what you might expect the jest-when usage to look like? Do you need a new when function, like constructedWith?

const Mock = jest.fn()
const instance = {}
when(Mock).constructedWith('foo').returnValue(instance)

Or are you asking for more? It sounds like you want new assertion features. But this library is for mocking, not really for asserting. It helps you set the return value based on arguments, it's up to you to assert against it.

You already have a great assertion feature expectCalledWith!

Perhaps I need to elaborate on my example with the definition of MyClass:

export class MyClass {
    public myFunction() { ... }
}

const myFunctionMock = jest.fn();
MyClass.prototype.myFunction = myFunctionMock; // use "spy on" - we replace a function with a mock for all instances of `MyClass` 
const instance = new MyClass();
instance.myFunction();

expect(myFunctionMock.mock.instances[0]).toBe(instance);
// here, we verified that `myFunctionMock` was invoked for the first time **exactly** on `instance` and not e.g. `instance2` or `instance3`.

It would be better to have a more nice-looking way to assert this, e.g. when(myFunctionMock).expectWasInvokedOn(instance) // verify that at least one instance in myFunctionMock.mock.instances contains the passed value

True. We have expectCalledWith but I don't love it. We also recently added verifyAllWhenMockedCalled and I like that one better. It verifies that each mock is called with the arguments in its calledWith function.

I don't want to add a large API surface that is custom. Whenever possible I want to piggyback off of jest's core API. So for class instance assertion, I'd highly prefer that we just use jest's built-in assertions. If it is too verbose then you can write a custom function to reduce the boilerplate.

If jest-when is not currently supporting something that the jest core supports we should fix that, but if you can successfully assert class instances (but just don't like the boilerplate) then I don't think there is anything to be done here.