<p>I'm trying to introduce a small change to an existing project without unit tests and decided I'd try to learn enough about nodejs and jest to include tests with my change. However, I cannot get mocks to work like I'd expect in, say, python. The project uses the &quot;kubernetes-client&quot; library from godaddy and tries to create a config object from the envvar &quot;KUBECONFIG&quot;, like this:</p>
<pre><code>// a few lines into server.js
// Instantiate Kubernetes client
const Client = require('kubernetes-client').Client
const config = require('kubernetes-client').config;
if (process.env.KUBECONFIG) {
    client = new Client({
        config: config.fromKubeconfig(config.loadKubeconfig(process.env.KUBECONFIG)),
        version: '1.13'
    });
}
else {
    client = new Client({ config: config.getInCluster(), version: '1.9' });
}
</code></pre>
<p>In my testing environment, I don't want any API calls, so I'm trying to mock it out:</p>
<pre><code>// __tests__/server.test.js
// Set up mocks at the top because of how server.js sets up k8s client
const k8sClient = require('kubernetes-client');
const narp = 'narp';
jest.mock('kubernetes-client', () =&gt; {
    const noConfigmaps = jest.fn(() =&gt; {
        throw narp;
    });
    const namespaces = jest.fn().mockReturnValue({
        configmaps: jest.fn().mockReturnValue({
            get: noConfigmaps
        })
    });
    const addCustomResourceDefinition = jest.fn().mockReturnThis()
    const mockClient = {
        api: {
            v1: {
                namespaces
            }
        },
        addCustomResourceDefinition: jest.fn().mockReturnThis(),
    };
    return {
        Client: jest.fn(() =&gt; mockClient),
        config: {
            fromKubeconfig: jest.fn().mockReturnThis(),
            loadKubeconfig: jest.fn().mockReturnThis(),
            getInCluster: jest.fn().mockReturnThis()
        },
    };
});
const app = require('../server.js')
const supertest = require('supertest');
const requestWithSuperTest = supertest(app.app);
describe('Testing server.js', () =&gt; {
    afterAll(() =&gt; {
        app.server.close();
    });
    describe('Tests with k8s client throwing error when fetching configmaps', () =&gt; {
        it(&quot;finds a resource's ingressGroup by name&quot;, () =&gt; {
            var resource = {
                &quot;spec&quot;: {
                    &quot;ingressClass&quot;: &quot;foo&quot;,
                    &quot;ingressTargetDNSName&quot;: &quot;foo&quot;
                }
            };
            var ingressGroups = [
                {
                    &quot;ingressClass&quot;: &quot;bar&quot;,
                    &quot;hostName&quot;: &quot;bar&quot;,
                    &quot;name&quot;: &quot;barName&quot;
                },
                {
                    &quot;ingressClass&quot;: &quot;foo&quot;,
                    &quot;hostName&quot;: &quot;foo&quot;,
                    &quot;name&quot;: &quot;fooName&quot;
                }
            ];
            expect(app.findMatchingIngressGroupForResource(resource, ingressGroups)).toBe(&quot;fooName&quot;);
        });

        it('GET /healthcheck should respond &quot;Healthy&quot;', async () =&gt; {
            const resp = await requestWithSuperTest.get('/healthcheck');
            console.log(&quot;Response in Testing Endpoints: &quot; + JSON.stringify(resp));
            expect(resp.status).toEqual(200);
            expect(resp.type).toEqual(expect.stringContaining('text'));
            expect(resp.text).toEqual('Healthy');
        });
        it('Tests getIngressGroups() rejects with error when it cannot get configmaps', async () =&gt; {
            app.getIngressGroups()
                .then()
                .catch(error =&gt; {
                    expect(error).toEqual(&quot;Failed to fetch Ingress Groups: &quot; + narp);
                });
        });
    });
});
</code></pre>
<p>With this setup, the tests pass (although I suspect it's meaningless). If I try to move the mocks inside the <code>describe</code> or <code>it</code> block using a <code>beforeEach</code> function (or not) so that I can change the behavior to return mock data instead of throwing an error, I immediately get errors with the k8s client complaining it can't find my kubeconfig/clusterconfig:</p>
<pre><code>$ npm run testj

&gt; testj
&gt; jest --detectOpenHandles

kubernetes-client deprecated require('kubernetes-client').config, use require('kubernetes-client/backends/request').config. server.js:45:44
kubernetes-client deprecated loadKubeconfig see https://github.com/godaddy/kubernetes-client/blob/master/merging-with-kubernetes.md#request-kubeconfig- server.js:49:42
 FAIL  __tests__/server.test.js
  ● Test suite failed to run

    ENOENT: no such file or directory, open 'NOT_A_FILE'

      44 | if (process.env.KUBECONFIG) {
      45 |     client = new Client({
    &gt; 46 |         config: config.fromKubeconfig(config.loadKubeconfig(process.env.KUBECONFIG)),
         |                                              ^
      47 |         version: '1.13'
      48 |     });
      49 | }

      at node_modules/kubernetes-client/backends/request/config.js:335:37
          at Array.map (&lt;anonymous&gt;)
      at Object.loadKubeconfig (node_modules/kubernetes-client/backends/request/config.js:334:28)
      at Object.eval [as loadKubeconfig] (eval at wrapfunction (node_modules/kubernetes-client/node_modules/depd/index.js:425:22), &lt;anonymous&gt;:5:11)
      at Object.&lt;anonymous&gt; (server.js:46:46)
</code></pre>
<p>If anybody has run into this kind of behavior before or sees some obviously-wrong lines, I'd really appreciate any tips or information. Thanks!</p>

<p>I had to change a few things to get this working:</p>
<ul>
<li><code>jest.doMock()</code> instead of <code>jest.mock()</code></li>
<li>use of <code>let app</code> inside the <code>describe</code> block instead of <code>const app</code> at module-scope</li>
<li>a <code>beforeEach()</code> which calls <code>jest.resetModules()</code></li>
<li>an <code>afterEach()</code> which calls <code>app.close()</code></li>
<li>in the <code>it</code> block which overrides the mock(s), explicitly call <code>jest.resetModules()</code> before overriding</li>
<li>in the <code>it</code> block which overrides the mock(s), call <code>app.close()</code> and re-initialize <code>app</code> before invoking the actual function-under-test/expect</li>
</ul>
<p>Resulting test file:</p>
<pre><code>// Set up mocks at the top because of how server.js sets up k8s client
const k8sClient = require('kubernetes-client');
const supertest = require('supertest');
const narp = 'narp';

describe('Testing server.js', () =&gt; {
    let app;
    let requestWithSuperTest;
    beforeEach(() =&gt; {
        jest.resetModules();
        jest.doMock('kubernetes-client', () =&gt; {
            const noConfigmaps = jest.fn(() =&gt; {
                throw narp;
            });
            const namespaces = jest.fn().mockReturnValue({
                configmaps: jest.fn().mockReturnValue({
                    get: noConfigmaps
                })
            });
            const addCustomResourceDefinition = jest.fn().mockReturnThis()
            const mockClient = {
                api: {
                    v1: {
                        namespaces
                    }
                },
                addCustomResourceDefinition: jest.fn().mockReturnThis(),
            };
            return {
                Client: jest.fn(() =&gt; mockClient),
                config: {
                    fromKubeconfig: jest.fn().mockReturnThis(),
                    loadKubeconfig: jest.fn().mockReturnThis(),
                    getInCluster: jest.fn().mockReturnThis()
                },
            };
        });
        app = require('../server.js');
        requestWithSuperTest = supertest(app.app);
    });
    afterEach(() =&gt; {
        app.server.close();
    });

    it(&quot;finds a Resource's ingressGroup by name&quot;, () =&gt; {
        var resource = {
            &quot;spec&quot;: {
                &quot;ingressClass&quot;: &quot;foo&quot;,
                &quot;ingressTargetDNSName&quot;: &quot;foo&quot;
            }
        };
        var ingressGroups = [
            {
                &quot;ingressClass&quot;: &quot;bar&quot;,
                &quot;hostName&quot;: &quot;bar&quot;,
                &quot;name&quot;: &quot;barName&quot;
            },
            {
                &quot;ingressClass&quot;: &quot;foo&quot;,
                &quot;hostName&quot;: &quot;foo&quot;,
                &quot;name&quot;: &quot;fooName&quot;
            }
        ];
        expect(app.findMatchingIngressGroupForResource(resource, ingressGroups)).toBe(&quot;fooName&quot;);
    });

    it('GET /healthcheck should respond &quot;Healthy&quot;', async () =&gt; {
        const resp = await requestWithSuperTest.get('/healthcheck');
        console.log(&quot;Response in Testing Endpoints: &quot; + JSON.stringify(resp));
        expect(resp.status).toEqual(200);
        expect(resp.type).toEqual(expect.stringContaining('text'));
        expect(resp.text).toEqual('Healthy');
    });
    it('Tests getIngressGroups() rejects with error when it cannot get configmaps', async () =&gt; {
        expect.assertions(1);
        await app.getIngressGroups()
            .catch(error =&gt; {
                expect(error).toEqual(&quot;Failed to fetch Ingress Groups: &quot; + narp);
            });
    });
    it('Tests getIngressGroups() succeeds when it gets configmaps', async () =&gt; {
        expect.assertions(1);
        jest.resetModules();
        jest.doMock('kubernetes-client', () =&gt; {
            const noConfigmaps = jest.fn(() =&gt; {
                console.log('Attempted to get mocked configmaps');
                return Promise.resolve({
                    body: {
                        items: []
                    }
                });
            });
            const namespaces = jest.fn().mockReturnValue({
                configmaps: jest.fn().mockReturnValue({
                    get: noConfigmaps
                })
            });
            const addCustomResourceDefinition = jest.fn().mockReturnThis()
            const mockClient = {
                api: {
                    v1: {
                        namespaces
                    }
                },
                addCustomResourceDefinition: jest.fn().mockReturnThis(),
            };
            return {
                Client: jest.fn(() =&gt; mockClient),
                config: {
                    fromKubeconfig: jest.fn().mockReturnThis(),
                    loadKubeconfig: jest.fn().mockReturnThis(),
                    getInCluster: jest.fn().mockReturnThis()
                },
            };
        });
        app.server.close();
        app = require('../server.js');
        await app.getIngressGroups()
            .then(result =&gt; {
                expect(result).toEqual([])
            });
    });
});
</code></pre>
