리액트 테스팅(1)

jest와 react-testing-library

2022-12-10

* Jest - Facebook에서 만든 테스팅 프레임 워크.

주로 단위 (unit) 테스트를 위해 사용.

All files inside "tests" folders


시작해보기

cra 폴더로 가서

npm test

파일명에 test가 들어간 파일을 찾는다.

a로 App.test.js에 있는 모든 테스트를 실행

test('renders learn react link', () => {
  render(<App />);
  const linkElement = screen.getByText(/learn react/i);
  expect(linkElement).toBeInTheDocument();
});
test('renders learn react link', () => {
  const { getByText } = render(<App />);
  const linkElement = getByText(/learn react/i);
  expect(linkElement).toBeInTheDocument();
});

아래 처럼도 쓸수 있다. (쿼리함수를 직접 쓰는 경우는 거의 없고 screen 객체로 이용)

<a
  className="App-link"
  href="https://reactjs.org"
  target="_blank"
  rel="noopener noreferrer"
>
  Learn React
</a>

linkElement가 Document안에 있는지 판단하는 matcher


쿼리함수

쿼리는 페이지에서 요소를 찾기 위해 테스트 라이브러리가 제공하는 방법


린트

"eslint-plugin-jest-dom"
"eslint-plugin-testing-library"

TDD(Test Driven Development)

실제 코드를 작성하기 전에 테스트 코드를 먼저 작성

간단한 카운팅 앱 만들어보기

test('Counter starts at 0', () => {
  render(<App />);
  // screen object로 원하는 엘리멘트에 접근(ID)
  const counterElement = screen.getByTestId('counter');
  // id가 counter인 엘리멘트의 텍스트가 0인가?
  expect(counterElement).toHaveTextContent(0);
});
import './App.css';
import {useState} from 'react';

function App() {
  const [count, setCount] = useState(0);

  return (
    <div className="App">
      <header className="App-header">
        <h3 data-testid="counter">{count}</h3>
      </header>
    </div>
  );
}

export default App;
test('Minus Button', () => {
  render(<App />);
  const buttonElement = screen.getByTestId('minus-button');
  expect(buttonElement).toHaveTextContent('-');
});

test('Plus Button', () => {
  render(<App />);
  const buttonElement = screen.getByTestId('plus-button');
  expect(buttonElement).toHaveTextContent('+');
});
<div>
  <button data-testid="minus-button">-</button>
  <button data-testid="plus-button">+</button>
</div>

FireEvent API

유저가 발생시키는 액션(이벤트)에 대한 테스트

test('When the + button is pressed, the counter change to 1', () => {
  render(<App />);
  const buttonElement = screen.getByTestId('plus-button');
  // 버튼 클릭
  fireEvent.click(buttonElement);
  // plus 버튼 클릭시 counter 엘리먼트는 1
  const counterElement = screen.getByTestId('counter');
  expect(counterElement).toHaveTextContent(1);
});

test('When the - button is pressed, the counter change to -1', () => {
  render(<App />);
  const buttonElement = screen.getByTestId('minus-button');
  // 버튼 클릭
  fireEvent.click(buttonElement);
  // minus 버튼 클릭시 counter 엘리먼트는 -1
  const counterElement = screen.getByTestId('counter');
  expect(counterElement).toHaveTextContent(-1);
});
const [count, setCount] = useState(0);

const handlePlus = () => {
  setCount((prevState) => prevState + 1);
};

const handleMinus = () => {
  setCount((prevState) => prevState - 1);
};

return (
  <div className="App">
    <header className="App-header">
      <h3 data-testid="counter">{count}</h3>
      <div>
        <button data-testid="minus-button" onClick={handleMinus}>
          -
        </button>
        <button data-testid="plus-button" onClick={handlePlus}>
          +
        </button>
      </div>
    </header>
  </div>
);

test('on/off button has blue color', () => {
  render(<App />);
  const buttonElement = screen.getByTestId('on/off-button');
  expect(buttonElement).toHaveStyle({backgroundColor: 'blue'});
});

test('Prevent -,+ button from being pressed when the on/off button is clicked', () => {
  render(<App />);
  const onOffButtonElement = screen.getByTestId('on/off-button');
  fireEvent.click(onOffButtonElement);
  const plusButtonElement = screen.getByTestId('plus-button');
  const minusButtonElement = screen.getByTestId('minus-button');
  expect(plusButtonElement).toBeDisabled();
  expect(minusButtonElement).toBeDisabled();
});
<button data-testid="on/off-button" style={{backgroundColor: 'blue'}} onClick={handleDisabled}>
  on/off
</button>