Enzyme 을 통한 DOM 시뮬레이션

Enzyme 은 airbnb 에서 만든 리액트 컴포넌트 테스팅 도구 입니다. 이 도구를 사용하면 더욱 세밀한 리액트 컴포넌트 테스팅을 할 수 있게 됩니다.

Enzyme 을 통해서 DOM 이벤트를 시뮬레이트 할 수도 있고 (예: 버튼 클릭, 인풋 수정, 폼 등록 등), 모든 라이프사이클이 문제없이 돌아가는지도 확인 할 수 있습니다.

설치 및 적용

Enzyme 을 사용하려면, 설치를 먼저 해줘야겠죠?

$ yarn add enzyme enzyme-adapter-react-16

그 다음엔 src 디렉토리에 setupTests.js 라는 파일을 생성해주겠습니다. - 이 파일은 CRA 로 만든 프로젝트에서 필요한 테스트 설정입니다.

src/setupTests.js

import { configure } from 'enzyme';
import Adapter from 'enzyme-adapter-react-16';

configure({ adapter: new Adapter() });

이 코드를 작성하고 나서, 기존에 실행중이던 yarn test 를 종료하고 새로 실행해주세요.

NameForm 테스트 코드 재작성

기존의 NameForm 테스트 코드에서 작성하던 react-test-renderer 대신에, Enzyme 을 사용해보겠습니다.

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

describe('NameForm', () => {
  let component = null;

  it('renders correctly', () => {
    component = shallow(<NameForm />);
  });

  it('matches snapshot', () => {
    expect(component).toMatchSnapshot();
  });
});

이렇게 하고, 터미널 상에서는 U 를 눌러서 스냅샷을 업데이트하세요.

Enzyme 을 사용한 기본 스냅샷은, 가독성이 좋지 않습니다.

ShallowWrapper {
  "length": 1,
  Symbol(enzyme.__root__): [Circular],
  Symbol(enzyme.__unrendered__): <NameForm
    onSubmit={[Function]}
/>,
  Symbol(enzyme.__renderer__): Object {
    "batchedUpdates": [Function],
    "getNode": [Function],
    "render": [Function],

이런 모양이죠.

이 값을 더 보기 좋은 형태로 변환하기 위해선 enzyme-to-json 이라는 jest 플러그인을 사용 하시면 됩니다. 다음 명령어를 통해 설치를 하고:

yarn add enzyme-to-json

package.json 에서 jest 값을 추가하세요.

package.json

{
  "name": "testing",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "enzyme": "^3.7.0",
    "enzyme-adapter-react-16": "^1.7.0",
    "react": "^16.6.3",
    "react-dom": "^16.6.3",
    "react-scripts": "2.1.1"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": "react-app"
  },
  "browserslist": [
    ">0.2%",
    "not dead",
    "not ie <= 11",
    "not op_mini all"
  ],
  "devDependencies": {
    "enzyme-to-json": "^3.3.4",
    "react-test-renderer": "^16.6.3"
  },
  "jest": {
    "snapshotSerializers": [
      "enzyme-to-json/serializer"
    ]
  }
}

이를 저장하고 난 다음엔, yarn test 를 새로 시작해야 적용이 됩니다.

DOM 시뮬레이션 해보기

자, 이제는 우리가 기존엔 할 수 없던, DOM 이벤트를 시뮬레이트 해보겠습니다. 우선, 결과물에 form 과 input 이 있는지 확인을 해보겠습니다.

src/components/NameForm.test.js

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

describe('NameForm', () => {
  let component = null;

  it('renders correctly', () => {
    component = shallow(<NameForm />);
  });

  it('matches snapshot', () => {
    expect(component).toMatchSnapshot();
  });

  describe('insert new text', () => {
    it('has a form', () => {
      expect(component.find('form').exists()).toBe(true);
    })
    it('has an input', () => {
      expect(component.find('input').exists()).toBe(true);
    })
  })
});

렌더링을 하고나면 selector 를 통하여 특정 DOM 을 선택 할 수 있습니다. 선택 방식은 css, prop 값, 컴포넌트, 태그명이 있습니다.

자, 이제 DOM 을 선택했으니 이벤트를 시뮬레이트 해봅시다.

src/components/NameForm.test.js

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

describe('NameForm', () => {
  let component = null;

  // 테스트용 onInsert 함수. changed 값을 바꿔줌
  let changed = null;
  const onInsert = (name) => {
    changed = name;
  }

  it('renders correctly', () => {
    component = shallow(<NameForm onInsert={onInsert} />);
  });

  it('matches snapshot', () => {
    expect(component).toMatchSnapshot();
  });

  describe('insert new text', () => {
    it('has a form', () => {
      expect(component.find('form').exists()).toBe(true);
    });
    it('has an input', () => {
      expect(component.find('input').exists()).toBe(true);
    });
    it('simulates input change', () => {
      const mockedEvent = {
        target: {
          value: 'hello'
        }
      };
      // 이벤트를 시뮬레이트 합니다. 두번째 파라미터는 이벤트 객체입니다.
      component.find('input').simulate('change', mockedEvent); 
      expect(component.state().name).toBe('hello');
    });
    it('simulates form submit', () => {
      const mockedEvent = {
        preventDefault: () => null // onSubmit 에서 preventDefault 를 호출하게 되므로, 가짜 함수 추가
      };
      component.find('form').simulate('submit', mockedEvent);
      expect(component.state().name).toBe(''); // 등록 하면 값이 공백으로 변하며
      expect(changed).toBe('hello');
    })
  })
});

자, 이제 모든게 작동했는지 확인해보세요! Enzyme 을 사용하면 위 처럼 특정 DOM 에 이벤트를 시뮬레이트 할 수 도 있지만, 특정 DOM 에 특정 문자열 이 들어있는지, 혹은 특정 props가 설정 되었는지, 등 정말 수많은 기능 들로 리액트 컴포넌트 테스팅을 할 수 있으니, 매뉴얼을 참고해보시길 바랍니다.

results matching ""

    No results matching ""