2022.08.10 - [IT/React] - RN(ReactNative) TDD TODO 앱 만들기 #3
데이터에 unique 한 id 를 부여하기
이전에 초기 데이터의 id 를 1,2,3 이렇게 넣었는데 좀 더 고유한 id 를 넣기 위해서 shortid 라는 라이브러리를 사용합니다
const initialData = [
{id: '1', subject: 'Learn React Native'},
{id: '2', subject: 'Create a React Native app'},
];
shortid 설치
npm install --save shortid
HomeScreen 에서 shortid 를 이용해서 id 값을 생성해줍니다
//HomeScreen.jsx
import React from 'react';
import Title from '../components/Title';
import TaskInput from '../components/TaskInput';
import TaskList from '../components/TaskList';
import shortid from 'shortid';
const initialData = [
{id: shortid.generate(), subject: 'Learn React Native'},
{id: shortid.generate(), subject: 'Create a React Native app'},
];
export default function App() {
console.log(initialData);
return (
<>
<Title title="Todo TDD" />
<TaskInput />
<TaskList data={initialData} />
</>
);
}
이제 id 값으로 zy3AZ01Zy 같은 고유값들이 생성되어서 들어가 있습니다
Task 추가 기능 만들기
TaskInput 에서 값을 입력하면 TaskInput value 에 적용되는 지 확인
Enter 키를 누르면 Task 추가 함수가 불러지는 지 확인
TDD 니깐 테스트 케이스 부터 추가한다
TaskInput-test.js 에 테스트 케이스 추가
import 'react-native';
import React from 'react';
import {render, fireEvent, cleanup} from '@testing-library/react-native';
import TaskInput from '../TaskInput';
describe('TaskInput Component Rendering', () => {
let wrapper;
let props;
beforeEach(() => {
props = {};
wrapper = render(<TaskInput {...props} />);
});
afterEach(cleanup);
it('should render placeholder', () => {
expect(wrapper.getByPlaceholderText('+ Add a Task')).toBeTruthy();
expect(wrapper.getByPlaceholderText('+ Add a Task')).toBeEnabled();
});
});
describe('TaskInput Component Interaction', () => {
let wrapper;
let props;
const inputText = 'Build a React Native App';
beforeEach(() => {
props = {
value: '',
onChangeText: jest.fn(),
onSubmitEditing: jest.fn(),
};
wrapper = render(<TaskInput {...props} />);
});
afterEach(cleanup);
it('Check Input Value empty', () => {
const element = wrapper.getByPlaceholderText('+ Add a Task');
expect(element.props.value).toBe('');
});
it('Should call onChangeText when typing', () => {
const element = wrapper.getByPlaceholderText('+ Add a Task');
fireEvent.changeText(element, inputText);
expect(element.props.onChangeText).toHaveBeenCalledTimes(1);
});
it('Should change input value when typing', () => {
const element = wrapper.getByPlaceholderText('+ Add a Task');
fireEvent.changeText(element, inputText);
expect(element.props.onChangeText).toBeCalledWith(inputText);
});
});
- wrapper, props 는 예전에 enzyme 에서 사용하던 형식으로 변경
- 랜더링 되는지
- 초기값이 '' 인지
- 값을 입력하면 onChangeText 함수가 호출되는지
- 값을 입력하면 onChangeText 함수로 값이 제대로 전달되는지
테스트 진행하면 당연히 싹 실패
랜더링만 성공이고 전부 실패
왜냐면 TaskInput 에서 props 를 정의 하지 않아서 값을 받을 수가 없어요
그럼 이제 TaskInput.jsx 수정
value 추가하고 테스트 = > 성공
onChangeText 를 TaskInput 에 props 추가 하고 테스트 => 성공
입력 버튼을 안 만들 거라서 Enter 치면 입력되도록 테스트 케이스를 추가한다
React Native Testing Library 에는 key Down, key Press 라는 개념이 없다 (엔터도 안드로이드, iOS 다르다)
onSubmitEditing 이벤트들 바로 호출해야 한다
it('Should call onSubmitEditing when pressing enter', () => {
const element = wrapper.getByPlaceholderText('+ Add a Task');
fireEvent.changeText(element, inputText);
fireEvent(element, 'onSubmitEditing');
expect(element.props.onSubmitEditing).toHaveBeenCalledTimes(1);
});
TaskInput 에 value, onChangeText, onSubmitEditing 을 추가해주니
const TaskInput = ({value, onChangeText, onSubmitEditing}) => {
return (
<TextInput
value={value}
onChangeText={onChangeText}
onSubmitEditing={onSubmitEditing}
style={styles.taskInput}
placeholder="+ Add a Task"
/>
);
};
깔끔하게 모든 테스트 통과
이제 컴포넌트 단위 테스트는 통과되었으니
coverage 한번 찍고 간다
HomeScreen 에 변경된 TaskInput 을 적용한다
HomeScreen-test 를 만들어준다
import 'react-native';
import React from 'react';
import {render, fireEvent, cleanup} from '@testing-library/react-native';
import HomeScreen from '../HomeScreen';
describe('HomeScreen Component Rendering', () => {
let wrapper;
let props;
const inputText = 'Build a React Native App';
beforeEach(() => {
props = {};
wrapper = render(<HomeScreen {...props} />);
});
afterEach(cleanup);
it('should render Title', () => {
expect(wrapper.getByText('Todo TDD')).toBeTruthy();
});
it('should add a new task', async () => {
const element = wrapper.getByPlaceholderText('+ Add a Task');
fireEvent.changeText(element, inputText);
fireEvent(element, 'onSubmitEditing');
await expect(wrapper.getByText(inputText)).toBeTruthy();
});
});
title 이 잘 나오는지
그리고 Task 를 추가하면 화면에 나오는지 테스트 케이스를 추가한다
테스트 케이스를 통과할 수 있게 HomeScreen 에 기능을 수정한다
//HomeScreen.jsx
import React from 'react';
import Title from '../components/Title';
import TaskInput from '../components/TaskInput';
import TaskList from '../components/TaskList';
import shortid from 'shortid';
const initialData = [
{id: shortid.generate(), subject: 'Learn React Native'},
{id: shortid.generate(), subject: 'Create a React Native app'},
];
export default function App() {
const [data, setData] = React.useState(initialData);
const [newTask, setNewTask] = React.useState('');
const handleInputTextChange = text => {
setNewTask(text);
};
const handleAddTask = () => {
setData([...data, {id: shortid.generate(), subject: newTask}]);
setNewTask('');
};
return (
<>
<Title title="Todo TDD" />
<TaskInput
value={newTask}
onChangeText={handleInputTextChange}
onSubmitEditing={handleAddTask}
/>
<TaskList data={data} />
</>
);
}
useState 로 전체 Task 를 관리하는 data 와 새로 입력되는 Task 인 newTask 를 추가하고
TaskInput 에서 Change 와 Submit 이벤트로 사용할 handle 함수를 만들어 주었다
그리고, TaskList 에 data 로 useState 로 만든 data 를 연결해주었다
테스트 전부 통과. Add a Task 로 추가하면 리스트에 적용
'IT > React' 카테고리의 다른 글
RN(ReactNative) TDD TODO 앱 만들기 #8 (0) | 2022.08.12 |
---|---|
RN(ReactNative) TDD TODO 앱 만들기 #7 (0) | 2022.08.12 |
RN(ReactNative) TDD TODO 앱 만들기 #6 (0) | 2022.08.12 |
RN(ReactNative) TDD TODO 앱 만들기 #5 (0) | 2022.08.12 |
RN(ReactNative) TDD TODO 앱 만들기 #3 (0) | 2022.08.10 |
RN(ReactNative) TDD TODO 앱 만들기 #2 (0) | 2022.08.10 |
RN(ReactNative) 앱 이름 변경하기 change app name (0) | 2022.08.09 |
RN(ReactNative) TDD 설정 및 TODO 앱 만들기 (0) | 2022.08.09 |