Testing Javascript Code

Jest

High-quality gold here: https://blog.sapegin.me/all/react-testing-2-jest-and-enzyme/

Test Structure

This testing tool is one of the best available right now and the documentation is pretty good (although you may really have to dig to find the right page.) It provides these test structure methods:

Test Assertions

Jest has its own assertion library built right in, which means you can use these common assertions (Jest calls them “matchers”).

Mocks

Whole Module Mock

Let’s say the module you are testing does this:

import * as hydrate from 'hydration-lab';

You can mock out that entire library and create a mock implementation by doing something like this:

jest.mock('sc-hydrate-sku', () => {
		return jest.fn((skus) => {
			return new Promise((resolve, reject) => {
				process.nextTick(() => {
					return resolve([
          {
						skuId: '3208505',
            media: { primaryImage: { altText: 'this is a image', path: '/cats/image' } }
          },
          {
						skuId: '4707100',
            media: { primaryImage: { altText: 'this is a image 2', path: '/cats/image' } }
          }
					]);
				});
			});
		});
	});

Here is a simpler example when you just want to prevent a method from doing its normal job.

jest.mock('./helpers/dataHelpers', () => ({
	fetchData: jest.fn()
}));

or even...

jest.mock('./helpers/dataHelpers');

Here is another example that checks to see if a method has been called. The really cool thing about this is we are mocking a function (hydrate) that is used inside our target module (./index.js).

import { hydrate } from 'hydration-lab';
jest.mock('react-dom'); // This will auto-mock all of the methods.

import { init } from './index';

describe('index.js', () => {
	beforeEach(() => {
		hydrate.mockClear();
	});

	describe('init', () => {
		it('should call hydrate', () => {
			init({ key: 'value'});
			expect(hydrate).toHaveBeenCalled();
		});

		it('should call hydrate without state', () => {
			init();
			expect(hydrate).toHaveBeenCalled();
		});
	});
});

Mocking a function on Window

Use this method when the function you are mocking is on the window object (it is probably an external dependency).

describe('app', () => {
	beforeEach(() => {
		const evtMngr = function () {};
		evtMngr.prototype.on = function () { return this; };
		evtMngr.prototype.trigger = function () { return this; };
		window.EventManager = new evtMngr();
	});
})

Overloading an Existing Function

This example mocks out the native Fetch API. This is useful when you want to test interaction with an external API.

describe('getGSPPlans', () => {
	it('should return undefined due to an error being thrown', () => {
		global.fetch = jest.fn().mockImplementation((url, data) => {
			const p = new Promise((resolve, reject) => {
				resolve({
					ok: false,
          headers: { get: () => 'application/json' },
          json: () =>
					new Promise((resolve, reject) => {
						resolve({
							yourResponse: 'data goes here'
						});
					})
        });
      });
      return p;
    });
    return getGSPPlans('s').then(data => {
			expect(data).toEqual(undefined);
    });
  });
});

Mocking isomorphic-fetch with fetch-mock

Fetch is part of browsers. Jest runs in Node, which does not have fetch, therefore it is common to polyfill Node with isomorphic-fetch. The easiest way to mock out fetch in that scenario is to use another package called fetch-mock.

import fetchMock from 'fetch-mock';
	
describe('YourModule', () => {
	it('Asynchronously fetches data', done => {
		fetchMock.get('/api/titles', {
			sample: 'data'
		});

		const yourMod = new YourModule();
		yourMod.getData().then(returnedData => {
			expect(returnedData).toEqual({
				sample: 'data'
			});
			done();
		});
	});
});

Enzyme

The Enzyme library is useful for testing React components.

Quick tip: To help get your bearings when selecting elements in your tests, you can log an HTML-like string representation of the component under test to the console by calling console.log(wrapper.debug());

Common React Assertions

Did component render anything?

const wrapper = shallow(<RewardsPaneContainer />);
expect(wrapper.find(RewardsPane).length).toEqual(1);

Testing a Component’s method

When testing a React component that has been extended from “Component” (e.g. class MyComp extends Component { ...) you may find that you need to test a custom method. In that case, get it from the instance.

const wrapper = shallow(<RewardsPaneContainer />);
const cookieValue = wrapper.instance().getUTCookieValue();
expect(cookieValue).toEqual(undefined);