Enzyme: jest.fn() value must be a mock function or spy.

Created on 1 Jun 2018  路  6Comments  路  Source: enzymejs/enzyme

Hi All, I'm following the following tutorial and having trouble implementing as I'm getting a warning when I run my tests.

https://egghead.io/courses/test-react-components-with-enzyme-and-jest

I have the following component which contains a function called onBlurItem

export class AdvancedItemSelection extends React.Component<ComponentProps> {

    constructor(props) {
        super(props);
    }

    onBlurItem(value, excluded = false) {
        if (!value.length) return;
        // call action here
    }

    render() {
        const { classes } = this.props;
        return (
            <>
                <Grid item lg={4}>
                    <Card elevation={2}>
                        <CardHeader className={classes.cardHeader} title={<Typography variant="title" >Include</Typography>} />
                        <CardContent>
                            <Grid item lg={12}>
                                <TextField
                                    fullWidth
                                    id="include-input"
                                    label="Include by Value"
                                    placeholder="Include"
                                    className={classes.textField}
                                    margin="normal"
                                    onBlur={e => e && this.onBlurItem(e.target.value)}
                                />
                            </Grid>
                        </CardContent>
                    </Card>
                </Grid>
            </>
        );
    }
}

I also have a test to simulate the onBlur event of the text field and whether that triggers my member function.

it("calls onBlur function when textField is blurred", () => {

    const tree = shallow(<AdvancedItemSelection  />);
    const input = tree.find("#include-input");
    input.simulate("change", {currentTarget: {value: "val123"}});
    input.simulate("blur");
    expect(tree.instance().onBlurItem).toBeCalledWith("val123", false);

}); 

when I execute the tests my output is:

jest.fn() value must be a mock function or spy. Received: function: [Function onBlurItem]

my current version of react and enzyme are:
react: "16.2.0"
enzyme: "3.3.0"

Most helpful comment

Thanks @mykhailo-riabokon , @twclark0 this was very useful. My final test looks like this.

    it("calls onBlur function when textField is blurred", () => {
        const props: ComponentProps  = {
          // omitted
        };
        const wrapper = shallow(<AdvancedItemSelection {...props} />) as any;
        const spy = jest.spyOn(wrapper.instance(), "onBlurItem");
        wrapper.instance().forceUpdate();
        wrapper.find("#include-input").simulate("blur", { currentTarget: { value: "foo"}}, spy);
        expect(spy).toBeCalledWith("foo");
    });

This is working as expected

馃憤

All 6 comments

Any help with this would be greatly appreciated.

@sean-killeen .toBeCalledWith() has to be called with jest's mock fn

https://facebook.github.io/jest/docs/en/expect.html#tohavebeencalledwitharg1-arg2-

Hi @sean-killeen

tree.instance().onBlurItem is an original function of AdvancedItemSelection class which is

onBlurItem(value, excluded = false) {
 if (!value.length) return;
 // call action here
}

and you can not expect toBeCalledWith function as it available with mocked functions only.

In order to test that it was called you need to mock it first. In order to do it you can use spyOn. And your test suite may look like

it("calls onBlur function when textField is blurred ", () => {
  // spy before creating an instance of a class
  const spy = jest.spyOn(AdvancedItemSelection.prototype, "onBlurItem");

  // preconditions 
  // simlute method call
  // assertion 

  // it's important to restore an orginal method as next test suite will use mocked version. 
  spy.mockRestore();
});

Also, I noticed that you simulate change with currentTarget and in your code you use target. So if your input implementation uses target simulate with currentTarget would not help you.

I hope it helps you.

Thanks @mykhailo-riabokon , @twclark0 this was very useful. My final test looks like this.

    it("calls onBlur function when textField is blurred", () => {
        const props: ComponentProps  = {
          // omitted
        };
        const wrapper = shallow(<AdvancedItemSelection {...props} />) as any;
        const spy = jest.spyOn(wrapper.instance(), "onBlurItem");
        wrapper.instance().forceUpdate();
        wrapper.find("#include-input").simulate("blur", { currentTarget: { value: "foo"}}, spy);
        expect(spy).toBeCalledWith("foo");
    });

This is working as expected

馃憤

Hi @sean-killeen

tree.instance().onBlurItem is an original function of AdvancedItemSelection class which is

onBlurItem(value, excluded = false) {
 if (!value.length) return;
 // call action here
}

and you can not expect toBeCalledWith function as it available with mocked functions only.

In order to test that it was called you need to mock it first. In order to do it you can use spyOn. And your test suite may look like

it("calls onBlur function when textField is blurred ", () => {
  // spy before creating an instance of a class
  const spy = jest.spyOn(AdvancedItemSelection.prototype, "onBlurItem");

  // preconditions 
  // simlute method call
  // assertion 

  // it's important to restore an orginal method as next test suite will use mocked version. 
  spy.mockRestore();
});

Also, I noticed that you simulate change with currentTarget and in your code you use target. So if your input implementation uses target simulate with currentTarget would not help you.

I hope it helps you.

@mykhailo-riabokon what if i have a functional component.. hooks i.e. ?

React provides no hooks into hooks, so there's no advanced testing tools available for them.

Please file a new issue if you have new questions.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

aweary picture aweary  路  3Comments

ahuth picture ahuth  路  3Comments

ivanbtrujillo picture ivanbtrujillo  路  3Comments

mattkauffman23 picture mattkauffman23  路  3Comments

abe903 picture abe903  路  3Comments