Jest Mock React Component ONLY in some tests
Asked Answered
L

2

7

This question is really good: Jest Mock module per test

It just don't answer my question on how to only mock it out in one single test and keep the rest using the original component.

That would make sense if I wish to do some mocking for an snapshot but not for the other tests

This is my current attempt

import React from 'react'
import { render } from '@testing-library/react'

jest.mock('components/Photo', () =>
  jest.fn(() => jest.requireActual('components/Photo'))
)
import Photo from 'components/Photo'

import PhotoGrid from '.'

beforeEach(() => {
  Photo.mockReset()
})

test('default renders 9 photos if provided 9', () => {
  const photos = [...Array(9).keys()]
  const { getAllByTestId, debug } = render(<PhotoGrid photos={photos} />)

  debug()
  expect(getAllByTestId(PHOTO_COMP_TEST_ID)).toHaveLength(9)
})

test('renders with masonry grid style', () => {
  Photo.mockImplementation(() => <div />)
  const photos = [...Array(9).keys()]
  const { container, debug } = render(<PhotoGrid photos={photos} />)

  debug()

  expect(container).toMatchInlineSnapshot(`
    <div>
      ... 
    </div>
  `)
})

This is the component to test

import React from 'react'
import Masonry from 'react-masonry-css'
import './index.css'

import Photo from 'components/Photo'

function PhotoGrid({ photos, numberOfPhotos = 9 }) {
  const imgs = photos ? photos.slice(0, numberOfPhotos) : []

  const breakpointColumnsObj = {
    default: 4,
    1300: 3,
    900: 2,
    700: 1,
  }

  return (
    <Masonry
      breakpointCols={breakpointColumnsObj}
      className="my-masonry-grid"
      columnClassName="my-masonry-grid_column"
    >
      {imgs &&
        imgs.map(({ id, secret, server, farm }, index) => (
          <div key={index} className="masonry-item">
            <Photo id={id} secret={secret} server={server} farm={farm} />
          </div>
        ))}
    </Masonry>
  )
}

export default PhotoGrid
Lattonia answered 14/8, 2020 at 9:34 Comment(1)
is that working ?Lac
P
7

I don't have the permission to add comments so I will just leave this here.

I have tried the solution offered by Han Daniels and I was getting the error:

TypeError: specificMockImpl.apply is not a function.

I have fixed it by adding .default after jest.requireActual('components/Photo') because Photo is the default export.

So it is: jest.requireActual('components/Photo').default

Pituri answered 18/8, 2022 at 14:51 Comment(1)
Thanks dude. I had the same problem. So, does this without default works only to no default exports?Befit
C
6

jest.mock(...) the component you want to mock in one of tests.

Use jest.requireActual(...) to implement default behavior.

Use mockImplementation to implement custom behavior.

import React from 'react'
import { render } from '@testing-library/react'

jest.mock('components/Photo')
import Photo from 'components/Photo'

import PhotoGrid from '.'

// This maintains the original implementation for tests. 
// This step is important because if not done, it will
// result in empty render errors.
beforeEach(() => {
  Photo.mockImplementation(jest.requireActual('components/Photo'));
}) 
 

// This test will use original implementation of 'components/Photo'
test('default renders 9 photos if provided 9', () => {
  const photos = [...Array(9).keys()]
  const { getAllByTestId, debug } = render(<PhotoGrid photos={photos} />)

  debug()
  expect(getAllByTestId(PHOTO_COMP_TEST_ID)).toHaveLength(9)
})

// This test will use the mocked implementation of 'components/Photo'
test('renders with masonry grid style', () => {
  Photo.mockImplementation(() => <div />)
  const photos = [...Array(9).keys()]
  const { container, debug } = render(<PhotoGrid photos={photos} />)

  debug()

  expect(container).toMatchInlineSnapshot(`
    <div>
      ... 
    </div>
  `)
})
Cosmopolite answered 21/1, 2021 at 19:22 Comment(4)
I'm getting TypeError: specificMockImpl.apply is not a function when I do this.Guillemette
This don't work with mockImplementationOnce.Befit
This don't work with typescriptCp
@EduardoLopes, @Kenji Miwa you'd need to cast the mocked function as a Jest Mock when using TypeScript. Something like this: (specificMockImpl as jest.Mock).mockImplementation(() => <div />);Matheny

© 2022 - 2024 — McMap. All rights reserved.