title: What is the proper way to stub dependencies when unit testing in TypeScript?
body: <p>I am migrating a set of Firebase Cloud Functions from Javascript to Typescript. With JS I was able to unit test with mocha, chai, and sinon and stub out various database dependencies for testing. With TS I am running into problems and unexpected behavior I don't understand.</p>
  
  <p>The pattern is something like:
  <code>mainFunction</code> calls <code>helperFunction</code> which calls <code>nestedHelperFunction</code>.</p>
  
  <p>I want to stub or spy on <code>nestedHelperFunction</code> in my tests when I call <code>mainFunction</code> with some test data.</p>
  
  <p><code>mainFunction</code> is in an <code>index.ts</code> and <code>helperFunction</code> and <code>nestedHelperFunction</code> are in something like a <code>utils.ts</code> file.</p>
  
  <p><em>Example of odd behavior</em></p>
  
  <pre class="lang-js prettyprint-override"><code>// index.ts
  import * as utils from './utils';
  
  
  export async function mainFunction() {
      console.log('Starting mainFunction...');
  
      const promiseResults = await Promise.all([
          Promise.resolve('One'),
          utils.helperFunction(),
          Promise.resolve('Three'),
      ]);
  
      console.log(promiseResults);
      return 1;
  }
  </code></pre>
  
  <pre class="lang-js prettyprint-override"><code>// utils.ts
  export async function helperFunction() {
      const newString = await nestedHelperFunction();
      return 'helperFunction Result | ' + newString;
  }
  
  export async function nestedHelperFunction() {
      return '***Nested***';
  }
  </code></pre>
  
  <p>Test file</p>
  
  <pre class="lang-js prettyprint-override"><code>//index.test.ts
  import * as myFunctions from '../index';
  import * as utils from '../utils';
  import * as sinon from 'sinon';
  import * as chai from 'chai';
  
  const expect = chai.expect;
  
  
  describe("Test Suite", () =&gt; {
  
      let functionSpy: sinon.SinonStub;
  
      beforeEach(() =&gt; {
          functionSpy = sinon.stub(utils, 'helperFunction');
          functionSpy.returns(Promise.resolve('Stubbed Function Results!'))
      });
  
      afterEach(() =&gt; {
          functionSpy.restore();
      });
  
      it('should resolve and call the correct functions.', async () =&gt; {
          const returnValue = await myFunctions.mainFunction();
  
          expect(returnValue).to.equal(1);
          expect(functionSpy.callCount).to.equal(1);
      })
  })
  </code></pre>
  
  <p><strong>Output:</strong>
  Tests pass and I get : <code>[ 'One', 'Stubbed Function Results!', 'Three' ]</code></p>
  
  <p>However, If I try to stub the <code>nestedHelperFunction</code> it does not work.</p>
  
  <pre class="lang-js prettyprint-override"><code>// index.test.js
  import * as myFunctions from '../index';
  import * as utils from '../utils';
  import * as sinon from 'sinon';
  import * as chai from 'chai';
  
  const expect = chai.expect;
  
  
  describe("Test Suite", () =&gt; {
  
      let functionSpy: sinon.SinonStub;
  
      beforeEach(() =&gt; {
          functionSpy = sinon.stub(utils, 'nestedHelperFunction'); // Changed
          functionSpy.returns(Promise.resolve('Stubbed Function Results!'))
      });
  
      afterEach(() =&gt; {
          functionSpy.restore();
      });
  
      it('should resolve and call the correct functions.', async () =&gt; {
          const returnValue = await myFunctions.mainFunction();
  
          expect(returnValue).to.equal(1);
          expect(functionSpy.callCount).to.equal(1);
      })
  })
  </code></pre>
  
  <p><strong>Output</strong>
  Test fails and I get unmodified output: <code>[ 'One', 'helperFunction Result | ***Nested***', 'Three' ]</code></p>
  
  <p>Why does it not work when stubbing <code>nestedHelperFunction</code> but works for  <code>helperFunction</code>?</p>
  
  <p><em>Working Example</em></p>
  
  <p>Something that works, but I don't understand why, is within <code>utils.ts</code> creating <code>helperFunction</code> and <code>nestedHelperFunction</code> as methods on a class instead of 'top level' functions.</p>
  
  <pre class="lang-js prettyprint-override"><code>// utils.ts
  
  export class Utils {
      static async helperFunction(): Promise&lt;string&gt; {
          const newString = await this.nestedHelperFunction();
          return 'helperFunction Result | ' + newString;
      }
  
      static async nestedHelperFunction (): Promise&lt;string&gt; {
          return '***Nested Output***';
      }
  }
  </code></pre>
  
  <p>Tests File</p>
  
  <pre class="lang-js prettyprint-override"><code>// index.test.ts
  import {mainFunction} from '../index';
  import {Utils} from '../utils';
  import sinon from 'sinon';
  import * as chai from 'chai';
  
  const expect = chai.expect;
  
  
  describe("Test Suite", () =&gt; {
  
      let functionSpy: sinon.SinonStub;
  
      beforeEach(() =&gt; {
          functionSpy = sinon.stub(Utils, 'nestedHelperFunction');
          functionSpy.returns(Promise.resolve('Stubbed Function Results!'));
      });
  
      afterEach(() =&gt; {
          functionSpy.restore();
      });
  
      it('should resolve and call the correct functions.', async () =&gt; {
          const returnValue = await mainFunction();
  
          expect(returnValue).to.equal(1);
          expect(functionSpy.callCount).to.equal(1);
      })
  })
  </code></pre>
  
  <pre class="lang-js prettyprint-override"><code>// index.ts
  import {Utils} from './utils';
  
  export async function mainFunction() {
      console.log('Starting mainFunction...');
  
      const promiseResults = await Promise.all([
          Promise.resolve('One'),
          Utils.helperFunction(),
          Promise.resolve('Three'),
      ]);
  
      console.log(promiseResults);
      return 1;
  }
  </code></pre>
  
  <p><strong>Output</strong>
  Tests pass and I get the desired/expect output: <code>[ 'One',
    'helperFunction Result | Stubbed Function Results!',
    'Three' ]</code></p>
  
  <p>Material I've read suggests to me something going on with importing es6 modules or how Typescript compiles and can change the names of imported items. In Javascript I was using Rewire to set stubs, some were private functions, but I had issues with that in Typescript.</p>
  
  <p>Thanks for any help.</p>