title: How do I correctly spyOn a react component's method via the class prototype or the enzyme wrapper instance?
body: <p>I am trying to assert that a React class component method is called when I simulate a click using Jest and Enzyme. When I try to spyOn the class prototype or <code>wrapper.instance()</code> I get <code>Error: Cannot spy the searchBooks property because it is not a function; undefined given instead</code>.</p>
  
  <p>My relevant dependencies:</p>
  
  <pre><code>"devDependencies": {
     "enzyme": "^3.9.0"
     "enzyme-adapter-react-16": "^1.6.0",
     "jest": "^23.6.0",
     "jest-enzyme": "^7.0.1",
     "ts-jest": "^23.10.3",
     "typescript": "^3.1.1",
  
    ...
  
  "dependencies": {
     "@material-ui/core": "^3.2.0",
     "@material-ui/icons": "^3.0.1",
     "@material-ui/lab": "^3.0.0-alpha.23",
     "react": "^16.5.2",
  
  </code></pre>
  
  <p>I have already tried these options, which throw the previously mentioned error.</p>
  
  <pre><code> let spy = jest.spyOn(wrapper.instance() as MyComponentClass, 'methodName');
   let spy2 = jest.spyOn(MyComponentClass.prototype, 'methodName');
  </code></pre>
  
  <p>I can remove the error with the following, but the spy still doesn't get called.</p>
  
  <pre><code>let spy3 = jest.spyOn(wrapper.find(MyComponentClass).instance() as MyComponentClass, 'methodName');
  </code></pre>
  
  <p>Below is my code.</p>
  
  <pre><code>import * as React from 'react';
  import { Fragment, Component, ChangeEvent } from 'react';
  import { AudioType } from '../../model/audio';
  import withStyles,  { WithStyles } from '@material-ui/core/styles/withStyles';
  import Typography from '@material-ui/core/Typography';
  import TextField from '@material-ui/core/TextField';
  import BookSearchStyles from './BookSearchStyles';
  import BookDetail from './BookDetail';
  import SearchIcon from '@material-ui/icons/Search';
  import IconButton from '@material-ui/core/IconButton';
  import { VolumeInfo } from '../../model/volume';
  
  export interface BookSearchProps extends WithStyles&lt;typeof BookSearchStyles&gt; {
      search?: (query: string) =&gt; void;
  }
  
  export interface BookSearchState {
      searchQuery?: string;
  }
  
  export class BookSearch extends Component&lt;BookSearchProps, BookSearchState&gt; {
      state: BookSearchState = {
          searchQuery: '',
      };
  
      handleChange = (event: ChangeEvent&lt;HTMLInputElement&gt;) =&gt; {
          this.setState({
              [event.target.name]: event.target.value,
          });
      };
  
      searchBooks = () =&gt; {
          if (this.state.searchQuery) {
              this.props.search(this.state.searchQuery);
          }
      };
  
      render() {
          const { classes, volumes } = this.props;
          return (
              &lt;Fragment&gt;
                  &lt;div className={classes.searchPrompt}&gt;
                      &lt;form className={classes.formContainer}&gt;
                          &lt;div className={classes.search}&gt;
                              &lt;TextField
                                  id="query-text-field"
                                  name="searchQuery"
                                  label="enter book title or author"
                                  className={classes.textField}
                                  value={this.state.searchQuery}
                                  onChange={this.handleChange}
                                  fullWidth={true}
                              /&gt;
                              {
                                  &lt;IconButton
                                      onClick={this.searchBooks}
                                      data-test="search-button"
                                  &gt;
                                      &lt;SearchIcon /&gt;
                                  &lt;/IconButton&gt;
                              }
                          &lt;/div&gt;
                      &lt;/form&gt;
                  &lt;/div&gt;
              &lt;/Fragment&gt;
          );
      }
  }
  
  export default withStyles(BookSearchStyles)(BookSearch);
  
  </code></pre>
  
  <p>My Test</p>
  
  <pre><code>import * as React from 'react';
  import { mount, ReactWrapper } from 'enzyme';
  import BookSearchWrapped from './index';
  import { BookSearch, BookSearchProps, BookSearchState } from './index';
  
  describe("&lt;BookSearch /&gt;", () =&gt; {
  
      let wrapper: ReactWrapper&lt;BookSearchProps, BookSearchState, BookSearch&gt;;
      let component: ReactWrapper&lt;BookSearchProps, BookSearchState&gt;;
      let search: (query: string) =&gt; void;
  
      beforeEach(() =&gt; {
          search = jest.fn();
          wrapper = mount(
              &lt;BookSearchWrapped
                  search={search}
              /&gt;
          );
          component = wrapper.find(BookSearch);
      });
  
      it('renders successfully', () =&gt; {
          expect(wrapper.exists()).toBe(true);
      });
  
      it("doesn't call props.search() function when the query string is empty", () =&gt; {
          let spy = jest.spyOn(wrapper.instance() as BookSearch, 'searchBooks'); //THROWS ERROR
          let spy2 = jest.spyOn(BookSearch.prototype, 'searchBooks'); //THROWS ERROR
          let spy3 = jest.spyOn(component.instance() as BookSearch, 'searchBooks'); //NOT CALLED
  
          wrapper.find(`IconButton[data-test="search-button"]`).simulate('click');
          expect(spy).toHaveBeenCalled();
          expect(spy2).toHaveBeenCalled();
          expect(spy3).toHaveBeenCalled();
          expect(search).not.toHaveBeenCalled();
      });
  });
  </code></pre>
  
  <p>Ideally, I should be able to do something like <a href="https://stackoverflow.com/questions/44769404/jest-spyon-function-called">Jest spyOn function called</a>.</p>