Skip to content

Instantly share code, notes, and snippets.

@wmonk
Created December 2, 2016 11:08
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save wmonk/4adba68a5ff499c8ce884df2f2dd1694 to your computer and use it in GitHub Desktop.
Save wmonk/4adba68a5ff499c8ce884df2f2dd1694 to your computer and use it in GitHub Desktop.

Unit testing react with Jest


What is a unit test?

  • When given some input, does the output look like x?
  • Runs quickly
  • Contained to a single unit of code (e.g. a function)
  • Written by developers, unlike acceptance tests

What isn't a unit test

  • Touches the database
  • Makes network requests (to APIs)
  • Touches the file system
  • It can't run at the same time as other unit tests
  • It has to run in a certain order

How are we going to test?


How should we write tests?

Discuss this

I propose BDD style:

describe('<Button />', () => {
  it('should invoke the onClick callback when clicked');
});

Behaviour driven development feels better suited to UI based testing rather than just functional definitions.


Testing a react component

This is a button component, what tests could we write?
const Button = ({ 
  onClick,
  text
}) => (
  <div onClick={onClick} className="button">
    {text}
  </div>
)

Some less useful:

// Implementation details inside tests
it('should return a <div />', () => {
  const tree = shallow(<Button text="Hello World" />);
  expect(tree.type()).toEqual('div');
});

it('should show passed text in .button', () => {
  const tree = shallow(<Button text="Hello World" />);
  const actual = tree.find('.button').text();
  expect(actual).toEqual('Hello World');
});


Some better tests:

it('should display the passed text prop', () => {
  const tree = shallow(<Button text="Hello World" />);
  expect(tree.text).toContain("Hello World");
});

it('should invoke onClick prop when clicked', () => {
  const spy = jest.fn();
  const tree = shallow(
    <Button
      text="Hello World
      onClick={spy} />
  );
  tree.simulate('click');
  expect(spy.calls).toEqual(1);
});

Shallow Rendering

  • Does not create DOM nodes
  • Returns objects describing your component tree
  • Does not render components outside the boundary of your component under test

Some enzyme gotchas

  • wrapper.simulate('click') will look for the onClick prop and invoke that
    • This means that it will invoke just the callback provided for that prop
  • Simulating events does not trigger with an Event
    • You must provide an object if you want it: wrapper.simulate('click', { id: 123 });

This is a more complex component tree

const SeatPrefs = ({ willReserve: boolean }) => (
  <div>
    <h3>Seating Preferences</h3>
    { willReserve && <div>
      <SeatSelections />
      <SeatLocations />
      <SmallNote /> 
    </div> }
  </div>
);

Only test the immediate children

☹️

it('should render a Direction selectbox');
it('should render a Position selectbox');
it('should render a CoachType selectbox');
it('should render a Table seat checkbox');
it('should render a Power Socket checkbox');
it('should render a Luggage Rack checkbox');
it('should render a Near Toilet checkbox');

😀

it('should render <SeatSelections /> when willReserve');
it('should render <SeatLocations /> when willReserve');
it('should render <SmallNote /> when willReserve');

SeatSelections must have it's own tests

SeatLocations must have it's own tests

SmallNote must have it's own tests


Discuss

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