Skip to main content

Command Palette

Search for a command to run...

Mocking an event handler

Updated
•3 min read•View as Markdown
Mocking an event handler
N

I am a self taught web developer owning experience of 12+ years in web development field.

There are multiple ways to mock an event handler in Jest Testing Framework. I will discuss two different scenarios and further, we will introspect each case.

Scenario1: Component accepts event handler as a prop

export const ProductView = ({ product, onClick }) => {
  ...
};

We need to test the onClick when the component is clicked. jest.fn is used to mock the handler.

const handleClick = jest.fn();

test('when clicked, calls onClick with productId', async() => {
    render('<ProductView product={product} onClick={handleClick} />')

    // click on the ProductView
    userEvent.click(screen.getByTestId('product'))

    // expect mock handler to be called
    expect(handleClick).toBeCalledTimes(1);
    expect(handleClick).toBeCalledWith(product.id)
})

PS: This is possible only because onClick is exposed as a prop. Another scenario to catch is if the component handled the click internally.

Scenario 2: Component handles the event internally

import { CartService } from '../../services';

export const ProductViewStandalone = ({
  product,
}) => {
  const { id, name, description, price, photo } = product;

  const handleClick = async () => {
    await CartService.addProduct(id);
  };

  return (
    <div testId="product" onClick={handleClick}>
      ...
    </div>
  );
};

In this situation, we can't mock the event handler because it is internal to the component. However, we know it calls CartService, which is an ES6 module.

Solution 1: Use jest.mock to mock the entire CartService module

Instead of mocking the event handler, we can mock the entire CartService module using jest.mock

// import CartService module so that we can mock it
import { CartService } from '../../services';

// automock the entire CartService module
jest.mock('../../services/CartService');

test('should calls addProduct with productId when clicked', async () => {
  const { getByTestId } = render(<ProductViewStandalone product={product} />)

  // click on the ProductView
  userEvent.click(getByTestId('product'));

  // expect addProduct to be called
  expect(CartService.addProduct).toBeCalledTimes(1);
  expect(CartService.addProduct).toBeCalledWith(product.id)
});

Solution 2: Use jest.mock with an explicit module implementation

This is same as solution 1, except that we provide an explicit module implementation instead of automocking the module.

const mockAddProduct = jest.fn();

// mock the CartService module and provide an implementation
jest.mock('../../services/CartService', () => {
 CartService: {
  addProduct: async (productId) => {
   // call mock function with productId to check later in test
   mockAddProduct(productId);
   return {
    items: [{productId, productName: 'iPhone', price: 899, quantity: 1}];
   }
 }
});

test('should calls onClick with productId when clicked', async () => {
   const { getByTestId } = render(<ProductViewStandalone product={product} />)

   // click on the ProductView
   userEvent.click(getByTestId('product'))

   // expect addProduct to be called
   expect(mockAddProduct).toBeCalledTimes(1);
   expect(mockAddProduct).toBeCalledWith(product.id);
});

Solution 3: Use jest.spyOn to mock an individual method

In this approach, we only mock one function in the CartService module. This is done using jest.spyOn. jest.synOn creates a mock function similar to jest.fn but also tracks calls to the specified method. For example:

// import CartService module so that we can mock it
import {CartService} from '../../services';

test('should calls onClick with productId when clicked', async () => {
   const spyAddProduct = jest.spyOn(CartService, 'addProduct');

   const { getByTestId } = render(<ProductViewStandalone product={product} />)

   // click on the ProductView
   userEvent.click(getByTestId('product'))

   // expect spyAddProduct to be called
   expect(spyAddProduct).toBeCalledTimes(1);
   expect(spyAddProduct).toBeCalledWith(product.id);
})

Motivation: https://github.com/nareshbhatia/react-testing-techniques

Know More: https://medium.com/engineered-publicis-sapient/react-testing-techniques-d97e9dd8f081

Comments (13)

Join the discussion
K

Your article contains excellent writing. slope game

H

https://www.chardhamtour.in/

L

In this situation, https://shellshockerss.co we cannot mock the event handler because it is internal to the component. However, we know that it calls CartService, which is an ES6 module.

K

nice [Kashmir Trip

H

Hi there! Nice stuff, do keep me posted when you post again something like this! Visit Us: https://www.gujaratexpert.com/

O
Otis Jame4y ago

JavaScript is a popular programming language that is often used to build web applications. https://amongus2.io One of the most common uses for JavaScript is to implement guard clauses in your code.

H

nice post

H

https://www.pilgrimagetour.in/

L

When you receive an event handler, https://nytwordle.io you can use it to perform some action based on the event. For example, you can set a timer to run when the user clicks a button.

H

https://www.kashmirtourpackage.org/

F
FNAF4y ago

Great. You are my favorite author. I always moviedle quordle love waiting for new articles from you, it's very informative I usually apply to life.

D
dy can4y ago

If you want to drive to a lot of locations but are blind on the road, or if you need to go to a lot of places but don't know which direction to go, go to my website right away. Mapquest driving directions will certainly satisfy you, and they can help you.

E

You have given useful information here. Nice job done by you. Keep going.

A

Nice piece of content. I was also searching for such information to provide assignment help on related topic. It’s good to be on this website. - https://www.qualityassignment.co.uk/

More from this blog

W

Web Chronicles

12 posts

I'm a Senior Full Stack Developer with 10+ years of experience. I strive to be a humble team player and be approachable to receive and give feedback.