Jest | 테스트 시작

Lumpen·2024년 11월 16일
0

TestCode

목록 보기
5/7

프론트엔드의 동작에는 서로 기반하여 빌드되는 흐름이 있기 때문에
단언을 여러개 선언해도 괜찮다 - 코드 중복 여부보다 알아보기 쉽고, 잘 동작하는지가 중요
테스트는 언제나 무언가를 렌더링 하면서 시작한다

red test

test("버튼이 빨간색으로 시작되어야 한다.", () => {
  render(<App />)
  const buttonElement = screen.getByRole('button', {name: /blue/i})
  expect(buttonElement).toHaveClass('red')
})

App 내에 만들 버튼을 테스트할 코드 작성 후 red test
아직 element 를 생성하지 않아 찾을 수 없다는 에러 발생

테스트 코드 내부가 비어있다면 통과한 것으로 나온다

blue test

function App() {
  return <div>
    <button className={'red'}>Change to blue</button>
  </div>
}

테스트 할 컴포넌트 작성 후 테스트에 통과되면
blue test 완료

logRoles

import { render, screen, fireEvent } from "@testing-library/react";
import {logRoles} from "@testing-library/react";
import App from "./App.jsx";

test("버튼이 빨간색으로 시작되어야 한다.", () => {
  const {container} = render(<App />) 
  logRoles(container)
  const buttonElement = screen.getByRole('button', {name: /blue/i})
  expect(buttonElement).toHaveClass('red')
})

HTMLElement 를 필수로 받아 text 에서 로그를 출력한다

만약 이미 작성된 컴포넌트가 있고, 테스트를 작성해야 할 때 유용하다

간단한 클릭 등의 이벤트에는 fireEvent 를 사용
복잡한 인터랙션에는 userEvent 를 사용할 수 있다

css test

위 예제처럼 class 를 사용하여 버튼 색상을 조절하는 것을 테스트한다면
실제로 css 파일 내에 class 가 있는지 확인해야 한다

css 를 직접 테스트 코드로 넣으면 조금 더 복잡해진다
jest 에서 css 를 해석하는 플러그인을 설치하여 진행할 수 있다
css 는 파싱도 느리고 테스트의 복잡성이 증대하기 때문에
테스트가 css 에 의존하지 않는 경우 config 에서 css 옵션을 false 로 주는 편이 좋다

toHaveStyle() 을 사용하면 css 를 가져와서 테스트를 할 수 있다
expect(buttonElement).toHaveStyle({ backgroundColor: 'blue'})
위와 같이 작성했다면 css blue 에 대한 색상을 찾지 못한다
css 값을 blue 로 줬더라도 테스트에서는 rgb 나 헥사코드 값을 줘야 찾을 수 있다
테스트 시에 색이 아니라 코드를 평가하는 것 같다

매칭되는 class name 에 정확하게 css 를 주고
클래스로 평가하는 편이 더 편리한 것 같다

수동 인수 테스트

TDD 에서 실제로 작동하는 앱을 확인할 순 없다
때문에 직접 눈으로 원하는 작업이 잘 완료되었는지 확인하려면
dev server 를 켜서 확인해야 한다

describe()

describe(): 테스트를 그룹화 할 수 있다
내부에서 여러개의 test() 작성 가능

간단한 구문의 경우 expect() 내에서 함수를 실행하라는데
잘모르겠다

describe() 로 그룹화한 테스트들 모두 각각의 테스트로 평가된다

jest 는 .test.js 로 파일을 찾아 테스트를 진행한다

userEvent

요소가 사라지거나 화면에서 숨김 처리 되었을 때의 테스트 또한 인터랙션으로 fireEvent 를 사용할 수 있다

userEvent 가 조금 더 안전하고 현실적인 시뮬레이팅 방식이라고 한다
fireEvent 는 DOM 이벤트를 발생시키는데 컴퓨팅 이벤트를 발생하는 것이고
userEvent 는 이벤트 전체를 시뮬레이팅 한다
실제 사용자 인터랙션을 더 완벽히 시뮬레이팅 하는 것
일부 동작은 userEvent로 지원 하지 않는다

import userEvent from '@testing-library/user-event'
test('test name', async () => {
	const user = userEvent.setup()
	await user.click(element)
})

setup() 메서드를 통해 유저 인스턴스 생성 후
이벤트 종류를 선택하여 사용한다
유저 이벤트는 항상 promise 를 반환한다
test 콜백에 async 함수로 작성하는 것을 기억하자..

popover

getBy 는 대상이 표시되지 않는 상태에는 이용할 수 없다

screen query methods

command

  • get: 요소가 DOM 내에 있을 것으로 기대한다
  • query: 요소가 DOM 내에 없을 것으로 기대한다
  • find: 요소가 비동기적으로 나타날 것으로 기대한다

[All]: 하나 이상의 매치를 기대할 경우 사용하여 매칭되는 전체의 배열을 얻을 수 있다

query type

무엇으로 검색할지

  • Role: 가장 선호되는 방식
  • AllText: 이미지 검색 시 사용됨
  • Text: 특정 역할이 없는 디스플레이 요소에 사용

Form elements

  • PlaceholderText
  • LabelText
  • DisplayValue

화면을 보고있는 사람이든 아니든 모두에게 해당하는 쿼리를 작성하는 것이 좋다
시멘틱 쿼리는 브라우저마다 일관성이 떨어지기 때문에 사용 시 주의해야 한다
text id 를 사용하는 것은 최후의 방법으로 권장되지 않는다

msw

mock service worker
service worker 를 통해 오프라인 상황을 지원한다
네트워크 호출을 가로채고 mocking 응답을 반환한다
브라우저나 노드 환경을 지원
코드 레벨이 아닌 네트워크 레벨에서 mocking 을 지원한다

간단한 앱에서는 모킹이 가능하지만 더 복잡한 앱에서는 MSW로 다양한 도구를 이용할 수 있다

설정 방법

npm install msw

  • create handlers
  • create test server
  • 테스트 수행 중 서버가 계속 돌아가야 한다
    - 하나의 테스트 종료 후 서버 핸들러 reset
    (테스트 도중 문제 발생 시에도 다음 테스트를 진행하도록)

handler

요청을 처리하는 함수들로 호출된 URL 을 확인해서 모의 응답을 반환한다

handlers.js

import {http, HttpResponse} from "msw";


export const handlers = [
  // rest api 를 사용하면 http / graphql 을 사용하면 graphql
  http.get('https://localhost:3030/scoops', () => {
    return HttpResponse.json([
      {name: 'Chocolate', imagePath: '/images/chocolate.png'},
      {name: 'Vanilla', imagePath: '/images/vanilla.png'},
    ])
  })
]

const handler = handlers[0]
console.log(handler)

server.js

import {setupServer} from "msw/node";
import {handlers} from "./handlers";

export const server = setupServer(...handlers);

src/setupTest.js

import "@testing-library/jest-dom";

import {beforeAll, afterEach, afterAll} from "vitest";
import {server} from "./mocks/server.js";

beforeAll(() => { server.listen() });
// API mocking test 이전 서버 실행

afterEach(() => { server.resetHandlers() });
// 각 test 사이 핸들러 리셋

afterAll(() => { server.close() });
// 모든 test 완료 후 서버 종료

함수 테스트

함수 테스트 시 반환값이
원시 타입이면 toBe()
객체 타입이면 toEqual()

profile
떠돌이 생활을 하는. 실업자, 부랑 생활을 하는

0개의 댓글