[react]3️⃣ TDD 방법으로 todolist-TodoItem

Grace·2021년 5월 5일
1

react-testing-library

목록 보기
3/5
post-thumbnail

TodoItem 만들기

이전 작업과 동일하게 TodoItem.js의 틀만 상태로 만들어 준 다음 작업 시작!

UI 구성하기

이 컴포넌트는 id, text, done 이 들어있는 todo 객체를 props로 받아와서
텍스트와 button을 보여주어야 한다.
이전에 만들었던 setup함수를 사용해서 테스트 코드를 작성해보면,

TodoItem.test.js

import React from 'react';
import TodoItem from './TodoItem';
import { render } from 'react-testing-library';

describe('<TodoItem />', () => {
  const sampleTodo = {
    id: 1,
    text: 'TDD 배우기',
    done: false
  };

  const setup = (props = {}) => {
    const initialProps = { todo: sampleTodo };
    const utils = render(<TodoItem {...initialProps} {...props} />);
    const { getByText } = utils;
    const todo = props.todo || initialProps.todo;
    const span = getByText(todo.text);
    const button = getByText('삭제');
    return {
      ...utils,
      span,
      button
    };
  };

  it('has span and button', () => {
    const { span, button } = setup();
    expect(span).toBeTruthy();
    expect(button).toBeTruthy();
  });
});

이 코드를 테스트에서 통과시키기 위한 코드를 짜자면,

TodoItem.js

import React from 'react';

const TodoItem = ({ todo }) => {
  const { id, text, done } = todo;

  return (
    <li>
      <span>{text}</span>
      <button>삭제</button>
    </li>
  );
};

export default TodoItem;

done 값에 따른 스타일 바꾸기

todo객체에 담겨있는 done이 true면 삭제선이 보이게, false면 없어지게 만들어보자~

TodoItem.test.js

...

  it('shows line-through on span when done is true', () => {
    const { span } = setup({ todo: { ...sampleTodo, done: true } });
    expect(span).toHaveStyle('text-decoration: line-through;');
  });

  it('does not show line-through on span when done is false', () => {
    const { span } = setup({ todo: { ...sampleTodo, done: false } });
    expect(span).not.toHaveStyle('text-decoration: line-through;');
  });

not이라는 키워드를 사용하게 되면 특정조건이 만족하지 않아야 한다는 것을 의미한다.
이번엔 클릭 이벤트까지 코드 작성을 마친 후 테스트 통과를 시켜보겠다.

클릭 이벤트 관리하기

TodoItme에서는 텍스트(span)와 삭제 버튼(button)을 클릭하면
클릭이벤트가 발생해야 한다.
그러기 위해 done값을 반전시키는 onToggle함수, 항목삭제를 하는 onRemove함수가 필요하다.
이 두 함수를 props로 전달받아서 함수들이 호출되게 한다.
여기서 함수들이 호출될 때에는 자신의 id를 파라미터로 넣어서 호출해야 하는걸 잊지말자!
그럼 테스트케이스를 작성해보자.

TodoItem.test.js

  it('calls onToggle', () => {
    const onToggle = jest.fn();
    const { span } = setup({ onToggle });
    fireEvent.click(span);
    expect(onToggle).toBeCalledWith(sampleTodo.id);
  });

  it('calls onRemove', () => {
    const onRemove = jest.fn();
    const { button } = setup({ onRemove });
    fireEvent.click(button);
    expect(onRemove).toBeCalledWith(sampleTodo.id);
  });

위의 테스트 케이스를 통과시키기 위해 컴포넌트 수정을 해준다.

TodoItem.js

import React from 'react';

const TodoItem = ({ todo, onToggle, onRemove }) => {
  const { id, text, done } = todo;

  return (
    <li>
      <span
        style={{
          textDecoration: done ? 'line-through' : 'none'
        }}
        onClick={() => onToggle(id)}
      >
        {text}
      </span>
      <button onClick={() => onRemove(id)}>삭제</button>
    </li>
  );
};

export default TodoItem;

여기서 최적화를 위해 useCallback함수를 사용해서 리팩토링을 해줄 수 있다.

const TodoItem = ({ todo, onToggle, onRemove }) => {
  const { id, text, done } = todo;
  
  const toggle = useCallback(() => onToggle(id), [id, onToggle]);
  const remove = useCallback(() => onRemove(id), [id, onRemove]);

  return (
    <li>
      <span
        style={{
          textDecoration: done ? 'line-through' : 'none'
        }}
        onClick={toggle}
      >
        {text}
      </span>
      <button onClick={remove}>삭제</button>
    </li>
  );
};

여기까지의 작업을 마치면 생성된 항목들에 대한 작업까지 마무리!
다음으로 지금까지 만든 TodoItem을 렌더링해주는 역할인
TodoItemList 작업을 해보자

profile
쉽게 사는건 재미가 없더군요, 새로 시작합니다🤓

0개의 댓글