Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to test below component in React using JEST

I created a component for Download File which takes some props and download the file on button click, its has two function which call showLoader and HideLoader

Component: Below is component code which takes some props and created a Download button on click that user download file.

import React from 'react'
import FileSaver from 'file-saver'
import axios from 'axios'

const DownloadFile = (props) => {

  const { url, title, callShowLoader, callHideLoader } = props

  const callDownloadFile = () => {
    callShowLoader()
    axios.get(url, { responseType: 'blob' }).then(res => {
      const fileName = res.headers['content-disposition'].match(/\"(.*?)"/)
      const fileToDownload = new Blob([res.data], {type: 'application/vnd.ms-excel;charset=charset=utf-8'})
      FileSaver.saveAs(fileToDownload, fileName[1])
      callHideLoader()
    })
  }

  return (<button className='mck-button-primary' title={title} onClick={e => callDownloadFile()}>
            <span className={"mck-icon__download mck-icon-no-pad"} />
          </button>)
}

export default DownloadFile

Test Here i am testing the component, not able to test when user clicks on button for download, its giving callShowLoader is not function error

import React from 'react'
import { shallow, mount } from 'enzyme'
import DownloadFile from '../index.js'
import toJson from 'enzyme-to-json'
import axios from 'axios'

describe('<DownloadFile />', () => {
  const props = {
    callHideLoader: jest.fn(),
    callShowLoader: jest.fn(),
    title: 'Download Excel Report'
  }

  it('should render button title properly', () => {
    const wrapper = shallow(<DownloadFile {...props}/>)
    expect(wrapper.find('button').prop('title')).toEqual(props.title)
  })

  it('should call download file', () => {
    const callShowLoader = jest.fn()
    const wrapper = shallow(<DownloadFile {...props} callShowLoader={callShowLoader} />)
    wrapper.find('button').simulate('click')
    expect(callShowLoader).toHaveBeenCalled()
  })

  it('should match intial layout', () => {
    const wrapper = shallow(<DownloadFile {...props}/>)
    expect(wrapper.getElements()).toMatchSnapshot()
  })
})
like image 870
Mukesh Avatar asked Jul 09 '18 06:07

Mukesh


2 Answers

The onClick prop on DownloadFile is completely ignored as you don't use it in the implementation of the DownloadFile component.

Initialize callShowLoader and callHideLoader with jest.fn(), pass them to the DownloadFile component (when you initialize mountWrapper), then simulate the onClick button and test whether callShowLoader and callHideLoader were both called.

like image 156
Robert Purcea Avatar answered Nov 07 '22 20:11

Robert Purcea


You're not passing callShowLoader as a prop in your tests, and therefore you'll get the callShowLoader is not a function error. Try this in your beforeEach

props = {
  callHideLoader: jest.fn(),
  callShowLoader: jest.fn(), 
  title: 'Download Excel Report'
}

and then in your test

it('should call callShowLoader upon click', () => {
  const button = mountWrapper.find('button')
  button.simulate('click')
  expect(props.callShowLoader).toHaveBeenCalled()
})

By the way I can't see any reason to use mount in those tests, shallow should do the work for you. I always write my shallows inside the test case to easily and fast see what the test is doing, like this

it('should call callShowLoader upon click', () => {
  const wrapper = shallow(<DownloadFile ...props />);
  const button = wrapper.find('button')
  button.simulate('click')
  expect(props.callShowLoader).toHaveBeenCalled()
})

And then I define pass the props that's necessary for the specific test inside the same test, to minimize the risk that the tests will break if I change something outside of the test. So in this case it would be

import React from 'react'
import sinon from 'sinon';
import { shallow, mount } from 'enzyme'
import DownloadFile from '../index.js'
import toJson from 'enzyme-to-json'

describe('<DownloadFile />', () => {
  const props = {
    callHideLoader: jest.fn(),
    callShowLoader: jest.fn(),
    title: '',
  };

  it('should render button title properly', () => {
    const title = 'Download Excel Report';
    const wrapper = shallow(<DownloadFile {...props} title={title} />);
    expect(wrapper.find('button').prop('title')).toEqual(title)
  })

  it('should call download file', () => {
    sinon.stub(axios, 'get').returns(Promise.resolve());
    const callShowLoader = jest.fn();
    const wrapper = shallow(<DownloadFile {...props} callShowLoader={callShowLoader} />);

    wrapper.find('button').simulate('click')
    expect(callShowLoader).toHaveBeenCalled()
    expect(axios.get.callCount).to.equal(1);
  })

  it('should match initial layout', () => {
    const wrapper = shallow(<DownloadFile {...props} />);
    expect(wrapper.getElements()).toMatchSnapshot()
  })
})

...but that's just a question of taste :-)

like image 1
kontrollanten Avatar answered Nov 07 '22 20:11

kontrollanten