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

When with literal object argument not working #209

Open
moahammadalt opened this issue Jan 7, 2021 · 4 comments
Open

When with literal object argument not working #209

moahammadalt opened this issue Jan 7, 2021 · 4 comments

Comments

@moahammadalt
Copy link

moahammadalt commented Jan 7, 2021

Whenever i call "when" with primitive type argument it gets work without any problems and the function return the desired value inside the test.

But when calling "when" with argument of reference type variables like literal object or a Map the function doesn't get mocked and it doesn't return the desired value from when.

 // it works fine and the function resolves true inside my test
when(browserNode.getStateChannel('some string')).thenResolve(true);

 // it doesn't work and the function doesn't resolve true inside my test
when(browserNode.getStateChannel({ channelAddress: 'some channel address'})).thenResolve(true);

is there any way to get "when" mocking works with literal objects arguments like above!

@EmilEriksen
Copy link

TLDR: You can use deepEqual or objectContaining i.e.

when(something.method(deepEqual({ ... })).thenResolve(true)

Without knowing the internals of ts-mockito this is likely due to the fact that object equality is checked by reference in JS. Being able to make sure a method is called with or returns an exact instance of an object is useful. For example (perhaps a bit contrived) consider an implementation of the identity function. You'd most likely not want the following implementation to pass.

const identity = x => ({...x})

Otherwise you'd end up with weird behavior like

const obj = { prop: 5 }
identity(obj) === obj // returns false

The following test would fail with this implementation of identity

const obj = { prop: 5 }
expect(identity(obj)).to.equal(obj) // fails

That being said in most situations like the one you mention, you probably don't care whether the object passed as argument matches exactly by reference. The actual behavior we want in most cases is probably closer to deepEqual or objectContaining but these matchers may also lead to unexpected behavior. Let's say you have some procedural style code and your client is supposed to call a method modifyAndReturnTrueOnSucess that modifies the object given as argument and you test looks like this

...
when(mock.modifyAndReturnTrueOnSucess(deepEqual(obj)).thenReturn(true))
...

but your client looks like this (it calls modifyAndReturnTrueOnSucess with a copy of the object)

...
thing.modifyAndReturnTrueOnSucess(copy(obj))
...
// at this point the code may assume obj was modified even though it was not - a copy of the object was

Your test may still pass even though modifyAndReturnTrueOnSucess was not called with the exact instance of the object that was supposed to be modified. This is because deepEqual essentially matches the argument by value.

@BBlackwo
Copy link

Thanks @EmilEriksen! Would be great to have deepEqual in the README docs! 🙂

@BBlackwo
Copy link

Looks like a PR has already been created #94. @NagRock could we get this merged in please?

@moahammadalt
Copy link
Author

Thanks guys, Can you merge the PR please so i can close this one as well

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

3 participants