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가 설정 되었는지, 등 정말 수많은 기능 들로 리액트 컴포넌트 테스팅을 할 수 있으니, 매뉴얼을 참고해보시길 바랍니다.