본문 바로가기

CodeSoom- React 13기

[코드숨] 리액트 13기 -3강/React-Testing(과제 1: To-do 테스트 작성하기)아샬 강의

context 를 하려면 plugin을 설치해야한다.

npm i -D jest-plugin-context

 

jest.config.js 에 아래 코드 추가

'jest-plugin-context/setup',

 

.eslintrc.js 파일에 아래 코드 추가

context: 'readonly',

 

context 를 사용하는 이유?

터미널에 아래 코드 치면

npx jest --watchAll --verbose

아래처럼 tast 결과가 나오게 돼서 추적하기 좋음

 

TEST coverage

npm run coverage

 

아직 진행중임 (옆에 18-36은 해야하는 line)

 


input.test.jsx

처음 내 제출 코드

import { render, fireEvent, screen } from '@testing-library/react';

import Input from './Input';

describe('Input', () => {
  const handleClick = jest.fn();
  const handleChange = jest.fn();
  const task = (
    <Input
      value="넷플릭스 보기"
      onChange={handleChange}
      onClick={handleClick}
    />
  );

  it('추가버튼을 누르면 onClick함수가 실행된다', () => {
    render(task);

    expect(handleClick).not.toBeCalled();

    fireEvent.click(screen.getByText('추가'));

    expect(handleClick).toBeCalled();
  });

  it('value값이 변경되면 onChange함수가 실행된다 ', () => {
    render(task);

    const input = screen.getByPlaceholderText('할 일을 입력해 주세요');

    fireEvent.change(input, {
      target: {
        value: '넷플릭스 보기',
      },
    });

    expect(input).toHaveAttribute('value', '넷플릭스 보기');
  });
});

 

아샬 코드

import {
  render, fireEvent,
} from '@testing-library/react';

import Input from './Input';

test('Input', () => {
  const handleChange = jest.fn();
  const handleClick = jest.fn();

  const { getByDisplayValue, getByLabelText, getByText } = render((
    <Input
      value="기존 할 일"
      onChange={handleChange}
      onClick={handleClick}
    />
  ));

  expect(getByDisplayValue('기존 할 일')).not.toBeNull();

  fireEvent.change(getByLabelText('할 일'), {
    target: { value: '무언가 하기' },
  });

  expect(handleChange).toBeCalled();

  fireEvent.click(getByText('추가'));

  expect(handleClick).toBeCalled();
});

 

종합해서 바꾼 내 코드

import { render, fireEvent } from '@testing-library/react';

import Input from './Input';

describe('Input', () => {
  const handleClick = jest.fn();
  const handleChange = jest.fn();

  it('추가버튼을 누르면 onClick함수가 실행된다', () => {
    const { getByText } = render((
      <Input
        value="넷플릭스 보기"
        onChange={handleChange}
        onClick={handleClick}
      />
    ));

    expect(handleClick).not.toBeCalled();

    fireEvent.click(getByText('추가'));

    expect(handleClick).toBeCalled();
  });

  it('value값이 변경되면 onChange함수가 실행된다 ', () => {
    const { getByDisplayValue, getByLabelText } = render((
      <Input
        value="넷플릭스 보기"
        onChange={handleChange}
        onClick={handleClick}
      />
    ));

    expect(getByDisplayValue('넷플릭스 보기')).not.toBeNull();

    fireEvent.change(getByLabelText('할 일'), {
      target: {
        value: '카페 가기',
      },
    });

    expect(handleChange).toBeCalled();
  });
});

 

여기서 '카페 가기'로 change가 되었는데 왜 아래같이 작성할 시, value값이 '카페 가기'로 변경이 안되고 기존 "넷플릭스 보기"가 나오는 가?

expect(getByLabelText('할 일')).toHaveAttribute('value', '카페 가기'); //X

 

Input의 역할은 handleChange 함수만 불러오는 것이기 때문이다.

위에서 '카페 가기'로 fireEvent.change가 된 것으로  handleChange 함수만 호출이 된다.

value값을 바꿔주는 역할은 App.jsx의 역할( handleChangeTitle함수..)


 

App.jsx 에서 만약 기본 title이 'aaa'로 되어 있다면

 

App.test.jsx(expect(getByText('aaa')).not.toBeNull(); 로 내용 확인 가능)

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

import App from './App';

describe('App', () => {
  const task = [
    {
      id: 1,
      title: 'aaa',
    },
  ];

  it('aaa', () => {
    const { getByText } = render((
      <App task={task} />
    ));

    expect(getByText(/추가/)).not.toBeNull();
    expect(getByText('aaa')).not.toBeNull();
    // not: 불일치여부확인 /toBeNull:null여부확인/추가가 null이 아닌지(있음=>통과)
  });

  // TODO:통합 테스트 코드 작성
  // CodeceptJS=>실제 브라우저에서 사용자 테스트 실행 가능.
});

List.jsx 내꺼 제출코드

import { render, fireEvent } from '@testing-library/react';

import List from './List';

describe('List', () => {
  const handleClickDelete = jest.fn();

  function renderList(tasks) {
    return render((
      <List
        tasks={tasks}
        onClickDelete={handleClickDelete}
      />
    ));
  }

  context('with tasks', () => {
    const tasks = [
      { id: 1, title: '넷플릭스 보기' },
      { id: 2, title: '카페 가기' },
    ];

    it('renders tasks', () => {
      const { getByText } = renderList(tasks);

      expect(getByText(/넷플릭스 보기/)).not.toBeNull();
      expect(getByText(/카페 가기/)).not.toBeNull();
    });

    it('renders "완료" button to delete a task', () => {
      const { getAllByText } = renderList(tasks);

      /* fireEvent.click(screen.getByText('완료'));
      `*AllBy*` variant of the query..오류=> buttons이 여러개이기때문에 오류가 생김
      */

      const buttons = getAllByText('완료');

      fireEvent.click(buttons[0]);

      expect(handleClickDelete).toBeCalledWith(1);// buttons[0]=>1번째꺼 고르게 했으니까 1
    });
  });

  context('without tasks', () => {
    it('renders no task message', () => {
      const tasks = [];

      const { getByText } = renderList(tasks);

      expect(getByText(/할 일이 없어요!/)).not.toBeNull();
    });
  });
});