When a JavaScript function is exported, it is straightforward to unit test. We can import it directly into our test and test the functionality. For example, we could use something like Jest to setup a simple import and unit test.

// foo.js

export function foo() {
  return 'bar';
}
// foo.spec.js

import { foo } from './foo.js'

describe('Foo', () => {
  describe('foo', () => {
    expect(foo()).toBe('bar');
  });
});

How would we test functions that we do not expose via export though?

There is a great tool, rewire, that allows getting references to functions that are not explicitly exported. Assuming you are using Babel, we can use babel-plugin-rewire to make the setup more simple.

  npm install babel-plugin-rewire --save-dev

Then we need to add it to our plugins for testing, in our babel.config.js.

...
plugins: [
  'babel-plugin-rewire',
  ...
]
...

We can then import the whole file, and get references to the non-exported functions, using __get__.

// bar.js

function _bar() {
  return 'baz';
}
// bar.spec.js

import Bar from './bar.js'

describe('Bar', () => {
  describe('_bar', () => {
    const _bar = Bar.__get__('_bar');
    expect(_bar()).toBe('baz');
  });
});

Rewire makes this setup downright magical, and saves us from needing to needlessly export things or use other hacks, just to get a reference to the function for testing. We can now ensure functions remain private, without all the headaches at testing time!