title: Cannot spy on mocked functions of a class using a manual mock
body: <blockquote>
    <p>Note: I have created a full paired down Github repo that you can download and checkout for yourself <a href="https://github.com/sethreidnz/manual-mock-issue-repro" rel="nofollow noreferrer">here</a></p>
  </blockquote>
  
  <p>I am trying to mock out a non-default exported class in a module using a manual mock in the folder <code>__mocks__</code> directly adjacent to the file. This works fine and I can get the mock to load correctly in my tests. However, if I export the mocked function as described <a href="https://jestjs.io/docs/en/es6-class-mocks#spying-on-methods-of-our-class" rel="nofollow noreferrer">here in the docs</a> it doesn't seem to actually give me a reference to the function that the mocked class calls in the test. This means when I call </p>
  
  <pre><code>expect(getAppDetailMock).toHaveBeenCalledTimes(1);
  </code></pre>
  
  <p>It fails as it has not been called at all. </p>
  
  <pre><code>expect(jest.fn()).toHaveBeenCalledTimes(expected)
  
  Expected number of calls: 1
  Received number of calls: 0
  </code></pre>
  
  <p>My suspicion is that it has something to do with the class itself ending up with a new version of the function, and not the very same reference I am importing... I say this because I did the exact same pattern to mock out a package in my <code>node_modules</code> which was <strong>not</strong> a class and it worked perfectly fine. </p>
  
  <p>Although you can check out the full code example <a href="https://github.com/sethreidnz/manual-mock-issue-repro" rel="nofollow noreferrer">here on github</a> I have copied my files below for full clarity. Any ideas on why this is not working as I would expect?</p>
  
  <pre><code>// api/__mocks__/clients.ts
  
  export const getAppDetailMock = jest.fn();
  export const AppsClient = jest.fn().mockImplementation(() =&gt; {
    return {
      getAppDetail: getAppDetailMock,
    };
  });
  
  </code></pre>
  
  <pre><code>// App.test.js
  
  import React from "react";
  import {
    render,
    screen,
    waitForElementToBeRemoved,
  } from "@testing-library/react";
  import App from "./App";
  import { getAppDetailMock } from "./api/__mocks__/clients";
  
  jest.mock("./api/clients");
  
  describe("&lt;App /&gt; ", () =&gt; {
    beforeEach(() =&gt; {
      getAppDetailMock.mockReset();
    });
    test("Should show not found message if app does not exist", async () =&gt; {
      const appId = "8500f5dd-8b41-4cb8-95fa-246b1f25855b";
      getAppDetailMock.mockResolvedValue(null);
      render(&lt;App appId={appId} /&gt;);
      await waitForElementToBeRemoved(() =&gt; screen.getByText("Loading"));
      expect(getAppDetailMock).toHaveBeenCalledTimes(1);
      expect(getAppDetailMock).toHaveBeenCalledWith(appId);
      expect(screen.getByText(`App not found found`)).toBeInTheDocument();
    });
    test("Should show not found message if app does not exist", async () =&gt; {
      const appId = "8500f5dd-8b41-4cb8-95fa-246b1f25855b";
      getAppDetailMock.mockResolvedValue({ appId });
      render(&lt;App appId={appId} /&gt;);
      await waitForElementToBeRemoved(() =&gt; screen.getByText("Loading"));
      expect(getAppDetailMock).toHaveBeenCalledTimes(1);
      expect(getAppDetailMock).toHaveBeenCalledWith(appId);
      expect(
        screen.getByText(`App found with id '${appId}'`)
      ).toBeInTheDocument();
    });
  });
  
  </code></pre>
  
  <pre><code>// App.tsx
  
  import React, { useState, useEffect } from "react";
  import "./App.css";
  
  import { AppsClient, AppDetailDto } from "./api/clients";
  
  type AppProps = {
    appId: string;
  };
  
  const App: React.FC&lt;AppProps&gt; = ({ appId }) =&gt; {
    const [hasLoaded, setHasLoaded] = useState(false);
    const [appDetail, setAppDetail] = useState&lt;AppDetailDto | null&gt;(null);
  
    useEffect(() =&gt; {
      const getAppDetail = async (appId: string) =&gt; {
        try {
          setHasLoaded(false);
          const result = await new AppsClient().getAppDetail(appId);
          setAppDetail(result);
          setHasLoaded(true);
        } catch (error) {}
      };
      if (!hasLoaded) {
        getAppDetail(appId);
      }
    }, [appId, hasLoaded]);
  
    if (!hasLoaded) {
      return &lt;&gt;Loading&lt;/&gt;;
    } else if (!appDetail) {
      return &lt;&gt;App not found found&lt;/&gt;;
    }
  
    return &lt;&gt;App found with id '{appDetail.appId}'&lt;/&gt;;
  };
  
  export default App;
  
  </code></pre>
  
  <pre><code>// api/clients.ts
  
  import { BaseClient } from "./baseClient";
  
  export interface AppDetailDto {
    appId: string;
  }
  
  export class AppsClient extends BaseClient {
    getAppDetail(appId: string): Promise&lt;AppDetailDto&gt; {
      return Promise.resolve({ appId });
    }
  }
  
  </code></pre>