개발/Next.js

NextJs 와 TypeScript ν™˜κ²½μ—μ„œ Jest , React-Testing-Library μ…‹νŒ…ν•˜κΈ° (μ‚½μ§ˆμ˜€μ§€κ²Œν•¨...)

밍(Ming) 🐈‍⬛ 2022. 10. 28. 20:28
728x90
λ°˜μ‘ν˜•

 

업무λ₯Ό λ³΄λ©΄μ„œ ν˜„μž¬ μ§„ν–‰ 쀑인 ν”„λ‘œμ νŠΈμ˜ μ½”λ“œλ₯Ό 쑰금 더 κ°œμ„ μ‹œν‚€κ³  μ•žμœΌλ‘œμ˜ μž‘μ—…μ„ νŽΈν•˜κ²Œ κ°€μ Έκ°€κΈ° μœ„ν•΄μ„œ μ–΄λ–€ 일듀을 ν•  수 μžˆμ„κΉŒ? ν•˜λŠ” 생각을 ν•˜λ‹€κ°€ ν…ŒμŠ€νŠΈ μ½”λ“œ μ…‹νŒ…μ„ ν•΄λ³΄μžλΌλŠ” 닀짐을 ν•˜κ²Œ λ˜μ—ˆλ‹€. ν˜„μž¬ μ§„ν–‰ 쀑인 μ½”λ“œμ—μ„œλŠ” ν•  수 μ—†κΈ° λ•Œλ¬Έμ— λΉ„μŠ·ν•œ ν™˜κ²½μ„ μ‘°μ„±ν•œ ν…ŒμŠ€νŠΈ μ½”λ“œλ₯Ό κ°€μ§€κ³  μ‹œν—˜ μ‚Όμ•„μ„œ ν…ŒμŠ€νŠΈ κ°œλ°œν™˜κ²½μ„ μ‘°μ„±ν•˜λ €κ³  μ‹œλ„ν–ˆλ‹€. 웬걸? μ‚½μ§ˆμ„ 이틀 μ‚¬ν˜ λ™μ•ˆ ν•˜κ³  λλƒˆλ‹€. ν•˜μ§€λ§Œ μ—¬μ „νžˆ 미ꢁ에 빠져있고 이걸 λ‹€μ‹œ μž¬μ—°ν•΄λ‚Ό 수 μžˆμ„κΉŒ? ν•˜λŠ” 의문이 κ°•ν•˜κ²Œ λ“€μ–΄μ„œ λ‹€κΈ‰ν•˜κ²Œ 이곳에 남겨보렀고 ν•œλ‹€. 

 

맨날 λ“£κΈ°λ§Œν•˜κ³  μ—¬κΈ°μ €κΈ° ꡬ글링 ν•˜λ‹€κ°€ 보기만 ν–ˆμ§€. μ •μž‘ 써본 적은 μ—†λŠ” ν…ŒμŠ€νŠΈ μ½”λ“œ. μ—¬λŸ¬ λΈ”λ‘œκ·Έλ₯Ό μ°Έκ³ ν•΄μ„œ 진행을 ν–ˆμ—ˆλŠ”λ°, λ­ν•˜λ‚˜ μ œλŒ€λ‘œ μ΄ν•΄ν•˜λŠ” 게 μ—†μœΌλ‹ˆ μ½”λ“œλŠ” μ™„μ „ 짬뽕이 되고 testλŠ” λ˜μ§€λ„ μ•Šκ³  κ·Έλž˜μ„œ 잘 λͺ¨λ₯΄κ² μœΌλ©΄ 뭐닀? κ³΅μ‹λ¬Έμ„œλ₯Ό 보자. 

 

 

Testing | Next.js

Learn how to set up Next.js with three commonly used testing tools — Cypress, Playwright, Jest, and React Testing Library.

nextjs.org

- Quick Start λΆ€ν„° λ³΄μ‹œλ©΄ λ©λ‹ˆλ‹€! 천천히 μ½μ–΄λ³΄μ‹œκ³  μ°¨κ·Όμ°¨κ·Ό μ‹œλ„ν•΄λ³΄λ©΄ λœλ‹€. λ‹Ήμ—°νžˆ λ¨Έλ¦¬μ—μ„œλŠ” μ₯κ°€ λ‚  것이닀. 

 

 

μ—¬κΈ°μ„œ μ‹œμž‘ν•΄μ„œ 였λ₯˜κ°€ λ‚œλ‹€λ©΄ κ·Έ 였λ₯˜λ“€μ„ ν•˜λ‚˜ν•˜λ‚˜μ”© ν—€μ³λ‚˜κ°€μžλΌκ³  μƒκ°ν–ˆλ‹€. 쉽지 μ•Šλ‹€. 

 

 

 

ν•„μš”ν•œ νŒ¨ν‚€μ§€ μ„€μΉ˜ν•˜κΈ°

μ—„μ²­ λ§Žμ€ νŒ¨ν‚€μ§€λ“€μ΄ ν•„μš”ν•˜λ‹€. 일단  jestλ₯Ό nextjs 와 μ‚¬μš©ν•˜κΈ° μœ„ν•œ 것도 ν•„μš”ν•˜κ³  typescript 와도 컴파일이 λ˜μ–΄μ•Ό ν•˜κΈ° λ•Œλ¬Έμ— 그에 λŒ€ν•œ μ—°κ΄€ νŒ¨ν‚€μ§€λ“€λ„ μ„€μΉ˜ν•΄μ€˜μ•Ό ν•œλ‹€.

 

npm install @testing-library/dom @testing-library/jest-dom @testing-library/react 
@testing-library/user-event babel-jest jest jest-dom ts-jest ts-loader

 

βœ”οΈ λ¦¬μ•‘νŠΈ μ»΄ν¬λ„ŒνŠΈλ₯Ό 가상 λΈŒλΌμš°μ €μ—μ„œ ν…ŒμŠ€νŠΈν•˜κΈ° μœ„ν•œ κΈ°λŠ₯을 μ œκ³΅ν•˜λŠ” @testing-library νŒ¨ν‚€μ§€λ“€,

βœ”οΈ babel-jestλŠ” ν…ŒμŠ€νŠΈ μ½”λ“œλ₯Ό λ³€ν™˜ν•˜κ³  μ»΄νŒŒμΌν•œλ‹€.

βœ”οΈ ts-jest, ts-loader λŠ” Jestμ—μ„œ νƒ€μž…μŠ€ν¬λ¦½νŠΈ 기반의 μ½”λ“œλ₯Ό ν…ŒμŠ€νŠΈν•  수 있게 ν•΄ μ€€λ‹€. 

 

ν…ŒμŠ€νŠΈκ°€ κ°€λŠ₯ν•œ μƒνƒœμ˜ package.json devDependencies

% API routes ν…ŒμŠ€νŠΈλ₯Ό μœ„ν•΄μ„œλŠ” node-mocks-http λΌλŠ” 것도 μ„€μΉ˜. 아직 μ „ κ·Έ λ‹¨κ³„κΉŒμ§€ λͺ»ν•΄μ„œ μš°μ„  μœ„μ˜ μ •λ„λ§Œ 해놓은 상황. node-mocks-httpλŠ” Next API routesλ₯Ό ν…ŒμŠ€νŠΈν•  λ•Œ ν•„μš”ν•œ request, response 객체의 mock을 생성해 μ€€λ‹€.

 

 

 

μΆ”κ°€ν•΄μ•Ό ν•   μ„€μ • νŒŒμΌλ“€

  • tsconfig.json

CNA에 νƒ€μž…μŠ€ν¬λ¦½νŠΈλ₯Ό λ”ν•΄μ„œ μ‚¬μš©ν–ˆλ‹€λ©΄ 이미 μƒμ„±λ˜μ–΄μžˆμ„ 파일둜 pathλΌλŠ” κ°’λ§Œ 더해주면 λœλ‹€. ν…ŒμŠ€νŠΈ μ½”λ“œ 적을 μ‹œμ— pathλ₯Ό 일일이 적지 μ•Šμ•„λ„ import ν•  수 있게 ν•΄ μ€€λ‹€.

{
  "compilerOptions" : {
      .....
      "path" : {
        '@components/*': ["components/*"],
        "@pages/*": ["pages/*"],
        "@styles/*":["hooks/*"]
      }
  }
}

 

 

  • jest.config.json
    κ³΅μ‹λ¬Έμ„œμ— λ³΄μ‹œλ©΄ λ””ν΄νŠΈλ‘œ λ‚˜μ™€μžˆλŠ” ν˜•μ‹. ν•˜μ§€λ§Œ css import 같은 κ²½μš°μ— mocksκ°€ μ—†λ‹€λ©΄ μ§€μš°κ³ , css도 ν•„μš”ν•˜μ‹œλ©΄ 폴더 λ§Œλ“€κ³  파일 λ§Œλ“€μ–΄μ„œ μ“°λ©΄ λœλ‹€. λ‚˜λŠ” ν•„μš” μ—†μ–΄μ„œ μ‹Ή μ§€μ›Œλ‚΄κ³ , page와 components만 남겼닀
// jest.config.json

module.exports = {
  collectCoverageFrom: [
    "**/*.{js,jsx,ts,tsx}",
    "!**/*.d.ts",
    "!**/node_modules/**"
  ],
  moduleNameMapper: {
    // Handle CSS imports (with CSS modules)
    // https://jestjs.io/docs/webpack#mocking-css-modules
    "^.+\\.module\\.(css|sass|scss)$": "identity-obj-proxy",

    // Handle CSS imports (without CSS modules)
    "^.+\\.(css|sass|scss)$": "<rootDir>/styles/__mocks__/styleMock.js",

    // Handle image imports
    // https://jestjs.io/docs/webpack#handling-static-assets
    "^.+\\.(jpg|jpeg|png|gif|webp|avif|svg)$": `<rootDir>/__mocks__/fileMock.js`,

    // Handle module aliases
    "^@pages/(.*)$": "<rootDir>/pages/$1",
    "^@components/(.*)$": "<rootDir>/components/$1"
  },
  setupFilesAfterEnv: ["<rootDir>/jest.setup.js"],
  testPathIgnorePatterns: ["<rootDir>/node_modules/", "<rootDir>/.next/"],
  testEnvironment: "jsdom",
  transform: {
    // Use babel-jest to transpile tests with the next/babel preset
    // https://jestjs.io/docs/configuration#transform-objectstring-pathtotransformer--pathtotransformer-object
    "^.+\\.(js|jsx|ts|tsx)$": ["babel-jest", { presets: ["next/babel"] }]
  },
  transformIgnorePatterns: ["/node_modules/", "^.+\\.module\\.(css|sass|scss)$"]
};

 

  • jest.setup.js

μœ„μ— μžˆλŠ” ν•­λͺ© 쀑에 이 νŒŒμΌμ„ 적은 곳이 μžˆμŠ΅λ‹ˆλ‹€. ν…ŒμŠ€νŠΈ μ‹€ν–‰ν•˜κΈ° 전에 λ°˜λ“œμ‹œ μ„ΈνŒ…ν•΄μ•Ό ν•˜λŠ” νŒŒμΌμž…λ‹ˆλ‹€. μ—­μ‹œλ‚˜ κ³΅μ‹λ¬Έμ„œμ—μ„œ 확인할 수 μžˆλ‹€. 크게 ν•  겉 μ—†κ³ , import만 ν•΄μ£Όλ©΄ μ˜€ν‚€λ„ν‚€

import '@testing-library/jest-dom/extend-expect'

 

  • package.json
"test" : "jest"

 

 

ν…ŒμŠ€νŠΈν•˜κΈ°

ν…ŒμŠ€νŠΈλ₯Ό μœ„ν•œ 폴더λ₯Ό ν•˜λ‚˜ λ§Œλ“€μ–΄μ£Όμž!

__test__ 폴더 μ•ˆμ— api , components, page λ“± 또 폴더λ₯Ό λ‚˜λˆ λ„ 되고 κ·Έλƒ₯ ν…ŒμŠ€νŠΈν•˜κ³  싢은 νŒŒμΌμ„ λ°”λ‘œ 써도 λœλ‹€.

 

μ—­μ‹œλ‚˜ ν…ŒμŠ€νŠΈ μ½”λ“œ μž‘μ„±μ— λŒ€ν•œ 뢀뢄도 κ³΅μ‹λ¬Έμ„œμ—μ„œ λ³Ό 수 μžˆλ‹€. 여기에도 μ •ν•΄μ§„ 룰이 μžˆμ–΄μ„œ 사싀 ν…ŒμŠ€νŠΈ μ½”λ“œλ₯Ό μž‘μ„±ν•˜λŠ” 것도 일이닀. μ΅μˆ™ν•΄μ§€κΈ°κ°€ 쉽지 μ•Šλ‹€. λ‚˜ μ—­μ‹œ λ‹¨μˆœνžˆ νŠΉμ • νŒŒμΌμ— ν…μŠ€νŠΈκ°€ μžˆλŠ”μ§€λ₯Ό ν™•μΈν•΄μ£ΌλŠ” ν…ŒμŠ€νŠΈ μ½”λ“œλ₯Ό 썼닀. 

 

// __test__/index.test.tsx

import { render, screen } from "@testing-library/react";
import Home from "@pages/index"; 

describe('Home', () => {
  it("render some text", () => {
   const { container } = render(<Home />);

    const home = screen.getByText('Home');

    expect(home).toBeInTheDocument();
    expect(container).toMatchSnapshot();
  });
});

 

 

 

 

ν…ŒμŠ€νŠΈ μ½”λ“œλ₯Ό λ‹€ μž‘μ„±ν–ˆλ‹€λ©΄? 터미널에 μ μ–΄λ³΄μž! 

npm test

 

 

 

"μ–΄?!" κΈˆμ§€μΈ 개발자 μ‚¬λ¬΄μ‹€μ—μ„œ "μ–΄!!!!!!!!"λ₯Ό μ™ΈμΉ˜κ²Œ ν•œ μˆœκ°„ 

 

 

μ΄λ ‡κ²Œ passκ°€ λ˜κΈ°κΉŒμ§€ λ§Žμ€ μ‹œκ°„μ΄ κ±Έλ Έλ‹€. κ·Έλ™μ•ˆ ν…ŒμŠ€νŠΈ μ½”λ“œμ— λŒ€ν•΄ λ§Žμ€ 글듀을 μ½μ—ˆλ‹€. μ½μœΌλ©΄μ„œ μœ λ‹› ν…ŒμŠ€νŠΈλΌκ³  ν•˜λ©΄ μ–΄λ””κΉŒμ§€μΈκ°€μ™€ ν˜„μ—…μ—μ„œ μ–΄λ””κΉŒμ§€ μ–΄λ–»κ²Œ ν…ŒμŠ€νŠΈν•΄μ•Ό ν•˜λŠ” 걸까?λΌλŠ” 생각이 λ“€μ—ˆλ‹€. λ‹¨μˆœν•˜κ²Œ λ²„νŠΌ λ‘œλ”©λ˜λŠ” κ²ƒλ§ŒμœΌλ‘œ ν…ŒμŠ€νŠΈν–ˆλ‹€κ³  ν•  수 μžˆμ„κΉŒ? μœ λ‹› ν…ŒμŠ€νŠΈλΌλŠ” 게 정말 그런 λΈŒλΌμš°μ € ν™˜κ²½μ˜ μž‘μ€ λ‹¨μœ„λ₯Ό λ§ν•˜λŠ” 것인가? 그것은 μ•„λ‹ˆλ‹€. λ‹Ήλ‹Ήν•˜κ²Œ 이런 ν…ŒμŠ€νŠΈ μ½”λ“œλ₯Ό μž‘μ„±ν•΄λ³΄μžκ³  μ œμ•ˆν•˜κ³  μ‹Άμ—ˆλŠ”λ° μ–΄λ””κΉŒμ§€ ν…ŒμŠ€νŠΈλ₯Ό μ§„ν–‰ν•΄μ•Ό ν•˜λŠ” 가에 λŒ€ν•œ 의문과 또 λ‹€λ₯Έ λ―ΈνŒ…μ„ κ°€μ Έμ˜¬ 것 같은 생각에 μ£ΌμΆ€λœλ‹€. 

 

 

 

 

μ°Έκ³ μžλ£Œλ“€

μ„€μΉ˜λΆ€ν„° - pass λ°›κΈ° μ „κΉŒμ§€ ν—˜λ‚œν–ˆλ˜ 였λ₯˜λ“€μ„ λ§Œλ‚˜μ„œ serching ν–ˆλ˜ 기둝듀이닀




 

 

 

728x90