Skip to content

Instantly share code, notes, and snippets.

@gravitinos
Last active October 8, 2018 22:20
Show Gist options
  • Select an option

  • Save gravitinos/68b48a9a5de5db553a0d1f3231630b75 to your computer and use it in GitHub Desktop.

Select an option

Save gravitinos/68b48a9a5de5db553a0d1f3231630b75 to your computer and use it in GitHub Desktop.

Picante Unit Testing

jest.mock('utils/Namespacing');
import React from 'react';
import ColorDot from '../ColorDot';
import { shallow } from 'enzyme';

const defaultProps = { color: 'red' };
const renderColorDot = newProps => {
  const props = { ...defaultProps, ...newProps };
  return shallow(<ColorDot {...props} />);
};

describe('ColorDot', () => {
  let colorDot;

  describe('with a child', () => {
    beforeEach(() => {
      colorDot = renderColorDot({ children: <div>Content</div> });
    });

    it('matches snapshot', () => {
      expect(colorDot).toMatchSnapshot();
    });
  });
});

What is the Point?

link to testing trophy/strategy docs define the purpose of unit tests and why we write them

Getting Started

Clone picante, npm run deps npm run test:unit to run all the tests.

Writing Tests

Create __unit__ folder as a sibling of the file you want to test. If you're testing src/Doubler.js you then want to create a src/__unit__/Doubler.spec.js . This file must be in a folder called __unit__ and end in .spec.js in order to be ran by jest.

If you have a function like so

// src/Doubler.js
const Doubler = number => number * 2;
export default Doubler;

then you might have a test that looks like

// src/__unit__/Doubler.spec.js

import doubler from '../Doubler';

describe('Doubler', () => {
  it('doubles', () => {
    expect(doubler(2)).toBe(4);
  });
});

Running Tests

npm run test:unit runs jest. This means you can give this command any option you can give jest, as long as all the options are after a -- (see more here)

... include stuff from first pass (pattern matching, —watch)

Debugging

The Jest Way

See here for using debuggers in your test Jest Debugging

VSCode extension

One tool that we have found especially useful is the vscode-jest plugin. Install Github

Best Practices

AAA

In most of our unit tests, we arrange, act, then assert.

import doubler from '../Doubler';

it('works', () => {
  const input = 2; // Arrange

  const result = doubler(input) // Act

  expect(result).toBe(4); //Assert
}) 

In this case, AAA may be a bit overkill. Maybe let’s make a better example?

describe('doubler', () => {
  describe('with 2', () => {
    beforeEach(() => {
      result = doubler(2);
    });

    it('works', () => {
      expect(result).toBe(4);
    });
  });
});

Mocking

jest.mock is used to mock functions that our units depend on. jest.mock('../SomeFile') makes it so that the SomeFile file is never used, and everything imported it is a function that returns undefined. you can give jest.mock a second arg to return an object that replaces the module. Typically we will set the mocked functions to the stub jest.fn() so that if we need to change their return value, we can do something like this:

jest.mock('../SomeFile', () => ({
  isLoading: jest.fn(),
}));

import { isLoading } from '../SomeFile';

describe('Thing', () => {
  describe('when content is loading', () => {
    beforeEach(() => {
      isLoading.mockReturnValue(true);
    });
  });

  describe('when content is loaded', () => {
    beforeEach(() => {
      isLoading.mockReturnValue(false);
    });
  });
});

if we don't want to change the mockReturnValue for the sake of the test, we can mock a module like such:

jest.mock('../SomeFile', () => ({
  isLoading: jest.fn(() => false),
});

...

With jest.mock if there is no second arg given, it uses the mock defined

Gotchas

jest.mock

When using jest.mock, it mocks the whole module. So if you are seeing a function that should be mocked is returning undefined, then you will need to supply your own implementation or mockReturnValue.

Expects + it blocks

Since jest runs each test in its own process, we should bias towards making multiple assertions on the same state inside an it block instead of two.

const name = 'Sam';
const modd = 'happy';
const getPerson = () => ({
  name,
  mood,
});

describe('an object', () => {
  let person;
  beforeEach(() => {
    person = getPerson();
  });
  
  // Bad
  
  it('has name', () => {
    expect(person.name).toBe(name);
  });
  
  it('has mood', () => {
    expect(person.mood).toBe(mood);
  });
  
  // Good
  it('has properties', () => {
    expect(person.name).toBe(name);
    expect(person.mood).toBe(mood);
  });
});

Snapshot

Jest Snapshot testing docs The first time jest snapshot tests are ran it will save (and create) the snapshot in a __snapshots__ folder next to the spec comparing against the snapshot. Then every output of the snapshot will be compared to the saved intended snapshot. If your snapshot changes, and you wish to update it, jest will prompt you when running the tests, in this case you press u.

React

When testing a react component, an ideal scenario is to take snapshots of the component with different expected props, and stubbing out functions that may cause side effects and assert they should have been called.

import { OurCustomButton } from '../OurCustomButton';
import { shallow } from 'enzyme';

const defaultProps = {
  disabled: false,
  onClick: jest.fn(),
};
const renderButton = newProps => {
  const props = {...defaultProps, ...newProps};
  return shallow(<OurCustomButton {...props} />);
};

describe('OurCustomButton', () => {
  let button;
  describe('when disabled', () => {
    beforeEach(() => {
      button = renderButton({ disabled: true });
    });

    it('is disabled', () => {
      expect(button).toMatchSnapshot();
    });
  });

  describe('when enabled', () => {
    beforeEach(() => {
      button = renderButton();
    });

    it('is enabled', () => {
      expect(button).toMatchSnapshot();
    });

    describe('after clicking', () => {
      beforeEach(() => {
        button.simulate('click');
      });

      it('calls onClick', () => {
        expect(defaultProps.onClick).toHaveBeenCalled();
      });
    });
  });
});

Enzyme

Shallow

In unit tests we want to shallow render.

Mount

We probably don't want to do this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment