Ad

How To Call Custom Methods Of React Component While Doing Unit Testing. I Am Using Typescript

I am using react with typescript. Can anyone tell me how to call the custom methods which is written in component inside unit testing.

I tried shallow and mount but I am not able to call custom methods.

import React  from 'react';
import {
  Theme,
  withStyles,
  createStyles,
} from '@material-ui/core';

export interface IFileUploadProps{}
export interface IFileUploadState {}

const styles = (theme: Theme) => {
  return createStyles({
    root: {
      paddingTop: theme.spacing(2),
      paddingBottom: theme.spacing(2),
      width: '100%',
      backgroundColor: 'inherit',
    },
    input: {
      display: 'none',
    },
    padding24: {
      paddingLeft: theme.spacing(3),
      paddingRight: theme.spacing(3),
    },
  });
};

class FileUpload extends React.Component<IFileUploadProps, IFileUploadState> {

    validateImage = () => {
      console.log('validate image');
    }

    render() {
      return <div>file upload</div>;
    }
  }

export default withStyles(styles)(FileUpload);

I need to do something like this.

import React from 'react';
import { shallow, configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16'
import FileUpload from './FileUpload';

configure({ adapter: new Adapter() });   
describe('FileUpload', () => {
  test('should call validateImage method correctly', () => {
    const wrapper = shallow(<FileUpload ></FileUpload>);
    wrapper.instance()['validateImage']();
  });
});

Here I am getting error.

TypeError: Cannot read property 'validateImage' of null

This error occurs when i export file using "export default withStyles(styles)(FileUpload);" When i use export default FileUpload it is working fine.

Ad

Answer

It should work. For example:

FileUpload.tsx:

import React from 'react';

interface IFileUploadProps {}
interface IFileUploadState {}

export class FileUpload extends React.Component<IFileUploadProps, IFileUploadState> {
  validateImage() {
    console.log('validate image');
  }

  render() {
    return <div>file upload</div>;
  }
}

FileUpload.spec.tsx:

import React from 'react';
import { shallow } from 'enzyme';
import { FileUpload } from './FileUpload';

describe('FileUpload', () => {
  test('should call validateImage method correctly', () => {
    const logSpy = jest.spyOn(console, 'log');
    const wrapper = shallow(<FileUpload></FileUpload>);
    expect(wrapper.text()).toBe('file upload');
    // @ts-ignore
    // tslint:disable-next-line: no-string-literal
    wrapper.instance()['validateImage']();
    expect(logSpy).toBeCalledWith('validate image');
  });
});

Unit test result with 100% coverage

 PASS  src/stackoverflow/58642342/FileUpload.spec.tsx
  FileUpload
    ✓ should call validateImage method correctly (14ms)

  console.log node_modules/jest-mock/build/index.js:860
    validate image

----------------|----------|----------|----------|----------|-------------------|
File            |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
----------------|----------|----------|----------|----------|-------------------|
All files       |      100 |      100 |      100 |      100 |                   |
 FileUpload.tsx |      100 |      100 |      100 |      100 |                   |
----------------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        4.487s, estimated 9s

Update 1

You should disable strict: true in your tsconfig.json file. Or, use // @ts-ignore to skip the static type check of tsc.

Update 2

Since you use HOC - the withStyles high order function, so you need use .dive([options]) => ShallowWrapper method of enzyme to get the shallow wrapper of FileUpload component.

FileUpload.tsx:

import React from 'react';
import { Theme, withStyles, createStyles } from '@material-ui/core';

interface IFileUploadProps {}
interface IFileUploadState {}

const styles = (theme: Theme) => {
  return createStyles({
    root: {
      paddingTop: theme.spacing(2),
      paddingBottom: theme.spacing(2),
      width: '100%',
      backgroundColor: 'inherit'
    },
    input: {
      display: 'none'
    },
    padding24: {
      paddingLeft: theme.spacing(3),
      paddingRight: theme.spacing(3)
    }
  });
};

class FileUpload extends React.Component<IFileUploadProps, IFileUploadState> {
  validateImage() {
    console.log('validate image');
  }

  render() {
    return <div>file upload</div>;
  }
}

export default withStyles(styles)(FileUpload);

FileUpload.spec.tsx:

import React from 'react';
import { shallow } from 'enzyme';
import FileUpload from './FileUpload';

describe('FileUpload', () => {
  test('should call validateImage method correctly', () => {
    const logSpy = jest.spyOn(console, 'log');
    const wrapper = shallow(<FileUpload></FileUpload>);
    expect(wrapper.dive().text()).toBe('file upload');
    // @ts-ignore
    // tslint:disable-next-line: no-string-literal
    wrapper
      .dive()
      .instance()
      ['validateImage']();
    expect(logSpy).toBeCalledWith('validate image');
  });
});

Unit test result with 100% coverage:

 PASS  src/stackoverflow/58642342/FileUpload.spec.tsx
  FileUpload
    ✓ should call validateImage method correctly (31ms)

  console.log node_modules/jest-mock/build/index.js:860
    validate image

----------------|----------|----------|----------|----------|-------------------|
File            |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
----------------|----------|----------|----------|----------|-------------------|
All files       |      100 |      100 |      100 |      100 |                   |
 FileUpload.tsx |      100 |      100 |      100 |      100 |                   |
----------------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        5.517s, estimated 12s

Source code: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/58642342

Ad
source: stackoverflow.com
Ad