NagRock / ts-mockito

Mocking library for TypeScript
MIT License
977 stars 93 forks source link

Verify store function call. #144

Closed grischenko-v closed 4 years ago

grischenko-v commented 5 years ago

I am trying to test store method call. When I run this test:

import * as React from 'react';
import {observer} from 'mobx-react';
import {mount} from 'enzyme';
import {instance, mock, verify, when} from 'ts-mockito';

class TestStore {
    onClick = () => {};
}

interface Props {
    store: any;
}

@observer
export class Test extends React.Component<Props, any> {
    render() {
        return (
            <div
                className={'test'}
                onClick={this.props.store.onClick}/>
        );
    }
}

describe('onclick test', () => {
    let testStoreMocked: any;
    let testStoreInst: any;
    let testElem: any;

    beforeEach(() => {
        testStoreMocked = mock(TestStore);
        testStoreInst = instance(testStoreMocked);
        testElem = mount<Test>(<Test
            store={testStoreInst}
        />);
    });

    test('test', () => {
        when(testStoreMocked.onClick).thenReturn();
        console.log(testElem.find('div.test').html());
        testElem.find('div.test').simulate('click');
        verify(testStoreMocked.onClick()).once();
    });
});

I get the error:

Expected "onClick()" to be called 1 time(s). But has been called 0 time(s).

      50 |         console.log(testElem.find('div.test').html());
      51 |         testElem.find('div.test').simulate('click');
    > 52 |         verify(testStoreMocked.onClick()).once();
         |                                           ^
      53 |     });
      54 | });

But this work fun:

import * as React from 'react';
import {observer} from 'mobx-react';
import {mount} from 'enzyme';
import {instance, mock, verify, when} from 'ts-mockito';

class TestStore {
    onClick = () => {};
}

interface Props {
    store: any;
}

@observer
export class Test extends React.Component<Props, any> {
    onClick = () => {
        this.props.store.onClick();
    };

    render() {
        return (
            <div
                className={'test'}
                onClick={this.onClick}/>
        );
    }
}

describe('onclick test', () => {
    let testStoreMocked: any;
    let testStoreInst: any;
    let testElem: any;

    beforeEach(() => {
        testStoreMocked = mock(TestStore);
        testStoreInst = instance(testStoreMocked);
        testElem = mount<Test>(<Test
            store={testStoreInst}
        />);
    });

    test('test', () => {
        when(testStoreMocked.onClick).thenReturn();
        console.log(testElem.find('div.test').html());
        testElem.find('div.test').simulate('click');
        verify(testStoreMocked.onClick()).once();
    });
});
ddrozdov commented 4 years ago

The problem is React passing an event argument to onClick, but since you don't use it in any way, you don't specify it in onClick signature. So method matchers length doesn't equal to arguments length.

What would be nice for such cases is a matcher that would match any number of arguments.

I found a workaround to use capture(testStoreMocked.onClick).first() instead of verify. It'll throw an exception if there was no onClick calls.

grischenko-v commented 4 years ago

Thank you!