# npm install
yarn install ๋๋ yarn
# npm i <package> --save
yarn add <package>
# npm i <package> --save-dev
yarn add <package> --dev : --dev ์ต์
์ -D ์ ๊ฐ๋ค.
# ํจํค์ง ์ญ์
yarn remove <package>
# dependencies์ devDependencies ๋ชจ๋ (package.json ์ ๋ช
์๋) version rule ์ ๋ฐ๋ผ ์ต์ ๋ฒ์ ์ผ๋ก ์
๊ทธ๋ ์ด๋.
# ๋ง์ฝ ์ด๋ค ํจํค์ง๊ฐ semantic versioning([segVer](https://github.com/semver/semver/blob/master/semver.md))๋ฅผ
# ๋ฐ๋ฅด์ง ์๋๋ค๋ฉด, version rule์ด ๋ฌด์ํด์ ธ ํ์ ํธํ์ฑ์ด ๋ณด์ฅ๋์ง ์๋ ์
๊ทธ๋ ์ด๋์ผ ์๋ ์๋ค.
yarn upgrade
# ํน์ ํจํค์ง๋ฅผ ํน์ ๋ฒ์ ์ผ๋ก ์
๊ทธ๋ ์ด๋
yarn upgrade <package>@<version>
# ๋ชฉ๋ก๋ค ์ค์์ ์ํ๋ ํจํค์ง๋ง ์ต์ ๋ฒ์ ์ผ๋ก ์
๊ทธ๋ ์ด๋ํ๋ interactive terminal ui ๋ฅผ ์ ๊ณตํ๋ค.
yarn upgrade-interactive
# production ํ๊ฒฝ์ ํ์ํ dependencies ๋ง ์ค์น
NODE_ENV=production yarn install ๋๋ yarn install --production
-
โ๏ธ ์ ์ดํ๋ฆฌ์ผ์ด์ ์ TEST ํด์ผ ํ ๊น?
- ๊ฐ๋จํ๊ฒ ๋ ์์ ์ ์ธ ์ดํ๋ฆฌ์ผ์ด์ ์ ์ํด์๋ ์ฌ๋ฌ ๋ฐฉ๋ฒ์ผ๋ก ํ ์คํธ๋ฅผ ํด์ค์ผ ๋ ์์ ์ ์ธ ์ดํ๋ฆฌ์ผ์ด์ ์ด ๋ ์ ์์ต๋๋ค.
-
โ๏ธ ํ ์คํ ์ผ๋ก ์ป๋ ์ด์ ์ ๋ฌด์์ผ๊น?
(1) ๋๋ฒ๊น ์๊ฐ์ ๋จ์ถ! ๋ง์ฝ ๋ฐ์ดํฐ๊ฐ ์๋ชป ๋์๋ค๋ฉด ๊ทธ๊ฒ์ด UI์ ๋ฌธ์ ์ธ์ง DB์ ๋ฌธ์ ์ธ์ง๋ฑ ์ ๋ถ ํ ์คํธ๋ฅผ ํด๋ด์ ์ฐพ์์ผ ํ๋๋ฐ ํ ์คํ ํ๊ฒฝ์ด ๊ตฌ์ถ๋์ด์๋ค๋ฉด ์๋ํ ๋ ์ ๋ ํ ์คํ ์ผ๋ก ํน์ ๋ฒ๊ทธ๋ฅผ ์ฝ๊ฒ ์ฐพ์ ๋ผ ์์์ต๋๋ค.
(2) ๋์ฑ ์์ ์ ์ธ ์ดํ๋ฆฌ์ผ์ด์ ! ๋ง์ ํ ์คํธ ์ฝ๋์ ํจ๊ป ์์ฑ๋ ์ฝ๋์ ์ดํ ๋ฆฌ์ผ์ด์ ์ด ๋๊ธฐ ๋๋ฌธ์ ํจ์ฌ ์์ ์ ์ธ ์ดํ๋ฆฌ์ผ์ด์ ์ด ๋ฉ๋๋ค.
(3) ์ด๋ฐ์๋ ์ฌ์ค๊ณ ์๊ฐ์ ๋จ์ถ, ์ถ๊ฐ๋ก ๋ฌด์ธ๊ฐ๋ฅผ ๋ ๊ตฌํํด์ผ ํ ๋ ๋ ์ฉ์ดํ ๊ฒ ํ ์ ์๋ ๋ฑ์ ์ด์ ๋ค์ด ์์ต๋๋ค.
-
โ๏ธ React Testing Library๋ ๋ฌด์์ธ๊ฐ?
-
Enzyme -> ๊ตฌํ ์ฃผ๋ ํ ์คํธ(Implementation Driven Test)
-
React Testing Library -> ํ์ ์ฃผ๋ ํ ์คํธ(Behavior Driven Test)
-
React Testing Library๋ React ๊ตฌ์ฑ ์์ ์์ ์ ์ํ API๋ฅผ ์ถ๊ฐํ์ฌ DOM Testing Library ์์ ๊ตฌ์ถ๋ฉ๋๋ค. DOM Testing Library๋ Dom ๋ ธ๋(Node)๋ฅผ ํ ์คํธํ๊ธฐ ์ํ ๋งค์ฐ ๊ฐ๋ฒผ์ด ์๋ฃจ์ ์ ๋๋ค. Create React App์ผ๋ก ์์ฑ๋ ํ๋ก์ ํธ๋ ์ฆ์ React Testing Library๋ฅผ ์ง์ํฉ๋๋ค. ๊ทธ๋ ์ง ์์ ๊ฒฝ์ฐ ๋ค์๊ณผ ๊ฐ์ด npm์ ํตํด ์ถ๊ฐํ ์ ์์ต๋๋ค.
- npm install --save-dev @testing-library/react
-
React Testing Library
๋ ์์ด๋น์ค๋น์์ ๋ง๋Enzyme์ ๋์ฒํ๋ ์๋ฃจ์
์ ๋๋ค. Enzyme์ด ๊ตฌ์ฑ ์์์ ๊ตฌํ ์ธ๋ถ ์ ๋ณด๋ฅผ ํ ์คํธํ๋ ๋์React Testing Library ๊ฐ๋ฐ์๋ฅผ React ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฌ์ฉ์
์ ๋๋ค. -
๊ตฌํ ์ฃผ๋ ํ ์คํธ(Enzyme)
์์๋ ์์ UI๋ฅผ ํ ์คํธํ ๋ ์ฃผ๋ก<p>
ํ๊ทธ๊ฐ ์ฐ์๊ณ Edit ๋ฑ์ ๋ฌธ์๊ฐ ๋ค์ด๊ฐ๋ค๋๊ฒ์ ํ ์คํธํฉ๋๋ค. ๊ทธ๋์ ๋ง์ฝ<p>
ํ๊ทธ๋ฅผ<h2>
ํ๊ทธ๋ก ๋ฐ๋๋ฉด ์๋ฌ๊ฐ ๋ ๊ฒ์ ๋๋ค. ํ์ง๋งํ๋ ์ฃผ๋ ํ ์คํธ(React Testing Library)
์์๋ ์ฌ์ฉ์์ ์ ์ฅ์์ ํ ์คํธ ํ๊ธฐ์<p>
ํ๊ทธ๊ฐ ์ฐ์ด๋<h3>
ํ๊ทธ๊ฐ ์ฐ์ฌ์ ๊ธ์ ํํํ๋์ง๊ฐ ์ค์ํ์ง ๋ณด๋ค ์ด๋ ํ ์ด๋ฒคํธ๋ฅผ ๋ฐ์์์ผฐ์๋ ํ๋ฉด์ด ์ด๋ป๊ฒ ๋ณํ๊ฐ ๋๋์ง ๊ฐ์ ํ ์คํธ๊ฐ ๋ ์ฃผ๋ฅผ ์ด๋ฃจ๊ฒ ๋ฉ๋๋ค
-
-
โ๏ธ Create React App์ผ๋ก ๋ฆฌ์กํธ ์์ํ๊ธฐ
npx create-react-app <ํ๋ก์ ํธ ์ด๋ฆ>
-
์๋ create-react-app์ ํ ๋ npm install -g create-react-app ์ด๋ ๊ฒ ํ์๋ค. global ๋๋ ํ ๋ฆฌ์ ๋ค์ด๋ฐ์
-
์ด์ ๋
npx
๋ฅผ ์ด์ฉํ์ฌ ๋ค์ด ๋ฐ์ง ์๊ณ ์ฌ์ฉ๊ฐ๋ฅํ๋ค.
-
-
โ๏ธ Jest๋ ๋ฌด์์ธ๊ฐ?
-
FaceBook์ ์ํด์ ๋ง๋ค์ด์ง ํ ์คํ ํ๋ ์ ์ํฌ์ ๋๋ค. ์ต์ํ์ ์ค์ ์ผ๋ก ๋์ํ๋ฉฐ Test Case ๋ฅผ ๋ง๋ค์ด์ ์ดํ๋ฆฌ์ผ์ด์ ์ฝ๋๊ฐ ์ ๋์๊ฐ๋์ง ํ์ธํด์ค๋๋ค. ๋จ์ (Unit) ํ ์คํธ๋ฅผ ์ํด์ ์ด์ฉํฉ๋๋ค.
-
Jest๊ฐ Test ํ์ผ์ ์ฐพ๋ ๋ฐฉ๋ฒ :
{filename}.test.js
/{filename}.spec.js
/All files inside "tests" folders
-
-
โ๏ธ Jest ํ์ผ ๊ตฌ์กฐ & ์ฌ์ฉ๋ฒ
-
"describe"
: ์ฌ๋ฌ ๊ด๋ จํ ์คํธ๋ฅผ ๊ทธ๋ฃนํํ๋ ๋ธ๋ก
์ ๋ง๋ญ๋๋ค. -
"it"
:๊ฐ๋ณ ํ ์คํธ(test)๋ฅผ ์ํํ๋ ๊ณณ
. ๊ฐ ํ ์คํธ๋ฅผ ์์ ๋ฌธ์ฅ์ฒ๋ผ ์ค๋ช ํฉ๋๋ค. -
"expect"
: expect ํจ์๋๊ฐ์ ํ ์คํธํ ๋๋ง๋ค ์ฌ์ฉ
๋ฉ๋๋ค. ๊ทธ๋ฆฌ๊ณ expect ํจ์ ํผ์์๋ ๊ฑฐ์ ์ฌ์ฉ ๋์ง ์์ผ๋ฉฐmatcher์ ํจ๊ป ์ฌ์ฉ
๋ฉ๋๋ค. -
"matcher"
:๋ค๋ฅธ ๋ฐฉ๋ฒ์ผ๋ก ๊ฐ์ ํ ์คํธ
ํ๋๋ก "matcher"๋ฅผ ์ฌ์ฉํฉ๋๋ค. -
"render"
: DOM์์ปดํฌ๋ํธ๋ฅผ ๋๋๋ง
ํ๋ ํจ์ /์ธ์๋ก ๋๋๋งํ React ์ปดํฌ๋ํธ( <App /> )๊ฐ ๋ค์ด๊ฐ
-
-
โ๏ธ Jest ์ฟผ๋ฆฌํจ์ & ์ฌ์ฉ๋ฒ
-
์ฟผ๋ฆฌ ํจ์
:ํ์ด์ง์์ ์์๋ฅผ ์ฐพ๊ธฐ ์ํด
ํ ์คํธ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์ ๊ณตํ๋ ๋ฐฉ๋ฒ / ์ฌ๋ฌ ์ ํ์ ์ฟผ๋ฆฌ("get", "find", "query")
=> ์ด๋ค ๊ฐ์์ฐจ์ด์
์ ์์๊ฐ ๋ฐ๊ฒฌ๋์ง ์์ผ๋ฉด ์ฟผ๋ฆฌ์์ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋์ง ๋๋ Promise๋ฅผ ๋ฐํํ๊ณ ๋ค์ ์๋ํ๋์ง ์ฌ๋ถ-
"getBy..."
: ์ฟผ๋ฆฌ์ ๋ํด์ผ์นํ๋ ๋ ธ๋๋ฅผ ๋ฐํ
ํ๊ณ ์ผ์นํ๋ ์์๊ฐ ์๊ฑฐ๋ ๋ ์ด์์ ์ผ์น๊ฐ ๋ฐ๊ฒฌ๋๋ฉด ์ค๋ช ์ค๋ฅ๋ฅผ ๋ฐ์์ํต๋๋ค(๋ ์ด์์ ์์
๊ฐ ์์๋๋ ๊ฒฝ์ฐ ๋์"getAllBy..."
์ฌ์ฉ). -
"queryBy..."
: ์ฟผ๋ฆฌ์ ๋ํด์ผ์นํ๋ ๋ ธ๋๋ฅผ ๋ฐํ
ํ๊ณ ์ผ์นํ๋ ์์๊ฐ ์์ผ๋ฉด null์ ๋ฐํํฉ๋๋ค. ์ด๊ฒ์ ์กด์ฌํ์ง ์๋ ์์๋ฅผ ์ด์ค์ ํ๋ ๋ฐ ์ ์ฉํฉ๋๋ค.๋ ์ด์์ ์ผ์น ํญ๋ชฉ์ด ๋ฐ๊ฒฌ
๋๋ฉด์ค๋ฅ๊ฐ ๋ฐ์
ํฉ๋๋ค(ํ์ธ๋ ๊ฒฝ์ฐ ๋์"queryAllBy"...
์ฌ์ฉ). -
"findBy..."
: ์ฃผ์ด์ง ์ฟผ๋ฆฌ์ ์ผ์นํ๋ ์์๊ฐ ๋ฐ๊ฒฌ๋๋ฉด Promise๋ฅผ ๋ฐํํฉ๋๋ค. ์์๊ฐ ๋ฐ๊ฒฌ๋์ง ์๊ฑฐ๋ ๊ธฐ๋ณธ ์ ํ ์๊ฐ์ธ 1000 ํ์ ๋ ์ด์์ ์์๊ฐ ๋ฐ๊ฒฌ๋๋ฉด ์ฝ์์ด ๊ฑฐ๋ถ๋ฉ๋๋ค.๋ ์ด์์ ์์๋ฅผ ์ฐพ์
์ผ ํ๋ ๊ฒฝ์ฐ"findAllBy..."
๋ฅผ ์ฌ์ฉํ์ญ์์ค. /findBy = getBy + waitFor
-
"waitFor"
:์ผ์ ๊ธฐ๊ฐ ๋์ ๊ธฐ๋ค๋ ค์ผ ํ ๋
waitFor๋ฅผ ์ฌ์ฉํ์ฌ ๊ธฐ๋๊ฐ ํต๊ณผํ ๋๊น์ง ๊ธฐ๋ค๋ฆด ์ ์์ต๋๋ค.
-
-
- npm5 ๋ถํฐ๋ --save ์ต์ ์ ๊ธฐ๋ณธ ์ต์ ์ผ๋ก ์ ์ฉํ๋ค. ์ฆ, --save๋ฅผ ์ฌ์ฉํ์ง ์์๋ dependencies์ ํญ๋ชฉ์ ์ถ๊ฐ๋๋ค.
โ๏ธ npm
JavaScript์ฉ Package Manager
โ๏ธ npm init
ํจํค์ง ์์กด์ฑ์ ๊ด๋ฆฌํ package.json ํ์ผ์ ๋ง๋๋ ๋ช
๋ น์ด
โ๏ธ npm install (plugin)
npm์ผ๋ก ํด๋น ํ๋ก์ ํธ์ ํจํค์ง(plugin)๋ฅผ ์ค์น
โ๏ธ npm install (plugin) --save
ํจํค์ง(plugin)๋ฅผ ./node_modules ๋๋ ํฐ๋ฆฌ์ ์ค์นํ๊ณ ./package.json ํ์ผ์ dependencies ํญ๋ชฉ์ ํจํค์ง ์ ๋ณด๊ฐ ์ ์ฅ๋ฉ๋๋ค.
--production ๋น๋ ์ ํด๋น ํจํค์ง๊ฐ ํฌํจ๋ฉ๋๋ค.
โ๏ธ npm install (plugin) --save-dev
ํจํค์ง(plugin)์ ./node_modules ๋๋ ํฐ๋ฆฌ์ ์ค์นํ๊ณ ./package.json ํ์ผ์ devDependencies ํญ๋ชฉ์ ํจํค์ง ์ ๋ณด๊ฐ ์ ์ฅ๋ฉ๋๋ค.
--production ๋น๋ ์ ํด๋น ํจํค์ง๋ ํฌํจ๋์ง ์์ต๋๋ค.
- ๐ฅ npx create-react-app react-test-app
- ๐ฅ npm install jest --save-dev
- ๐ฅ npm test
-
โ๏ธ Eslint ์ค์ ํ์ผ ์์ฑ
-
package.json์ eslintConfig ๋ถ๋ถ ์ ๊ฑฐ
-
.eslintrc.json ํ์ผ ์์ฑ
-
Plugins : eslint์์ ๊ธฐ๋ณธ์ผ๋ก ์ ๊ณตํ์ง ์๋ ๋ค์ํ ๊ท์น์ ํ๋ฌ๊ทธ์ธ์ ํตํด ์ฌ์ฉํ ์ ์์ต๋๋ค.
-
eslint: ESLint ์ฝ์ด
-
eslint-plugin-react: React ๊ด๋ จ ๋ฆฐํธ ์ค์ ์ ์ง์
-
eslint-plugin-react-hooks: React Hooks์ ๊ท์น์ ๊ฐ์ ํด์ฃผ๋ ํ๋ฌ๊ทธ์ธ
-
eslint-plugin-import: ES2015+์ import/export ๊ตฌ๋ฌธ์ ์ง์
-
eslint-plugin-jsx-a11y: JSX ๋ด์ ์ ๊ทผ์ฑ ๋ฌธ์ ์ ๋ํด ์ฆ๊ฐ์ ์ธ AST๋ฆฐํ ํผ๋๋ฐฑ์ ์ ๊ณต
-
eslint-config-prettier: prettier์ eslint์ ์ถฉ๋์ ์ผ์ผํค๋ ESLint ๊ท์น๋ค์ ๋นํ์ฑํ์์ผ์ฃผ๋ config
-
eslint-plugin-prettier: prettier์์ ์ธ์ํ๋ ์ค๋ฅ๋ฅผ ESLint๊ฐ ์ถ๋ ฅ // ์ฌ์ฉํด๋ ๋์ง๋ง ๋น์ถ
-
eslint-config-airbnb: airbnb์ฌ์ ์ฝ๋ฉ๊ท์น์ ์ฌ์ฉ
-
npm eslint-plugin-react eslint-plugin-react-hooks eslint-config-prettier --save-dev
-
๋ด๋ถ ์ค์
-
env : ์ฌ์ ์ ์๋ ์ ์ญ ๋ณ์ ์ฌ์ฉ์ ์ ์ / ์์ฃผ ์ฌ์ฉ๋๋ ์ค์ ์ผ๋ก๋ browser, node
-
parserOptions : ESLint ์ฌ์ฉ์ ์ํด ์ง์ํ๋ ค๋ Javascript ์ธ์ด ์ต์ ์ ์ง์
-
plugins : ํ๋ฌ๊ทธ์ธ ์ถ๊ฐ => ์ถ๊ฐ ํ ๋, eslint-plugin- ๋ถ๋ถ ์๋ต ๊ฐ๋ฅ
-
extends : ๊ท์น ์ค์ => ํ๋ฌ๊ทธ์ธ์ ์ถ๊ฐ ํ ํ์ ๊ท์น์ ์ ํด์ค์ผ ์ฌ์ฉ ๊ฐ๋ฅ / react๋ฅผ ์ํ ๊ท์น recommended๋ ์ถ์ฒ์ด ๋๋ ๊ฑธ ์ฌ์ฉ
-
rule : ๊ท์น ๋ณ๊ฒฝ
-
-
-
React_Test(Jest)์ผ๋
-
eslint-plugin-testing-library :
render๋ก Dom ๊ทธ๋ฆฌ๋ ๋ถ๋ถ
-
eslint-plugin-jest-dom :
expect-matcher๋ก ํ ์คํธ
-
npm install eslint-plugin-testing-library eslint-plugin-jest-dom --save-dev
// src/eslintrc.json { "plugins": ["testing-library", "jest-dom"], "extends": [ "react-app", "react-app/jest", "plugin:testing-library/react", "plugin:jest-dom/recommended" ] }
-
-
-
โ๏ธ Prettier ์ค์น ๋ฐ ์ค์
- npm์ผ๋ก ์ค์น : ์ฌ๋ฌ ๊ฐ๋ฐ์์ ๊ฐ์ ํฌ๋งท ์ ์ง์ ๋ ์ข์
{ "singleQuote": false, // ๋ฌธ์์ด์ ๋ฐ์ดํ๋ก formatting "semi": true, // ์ฝ๋ ๋ง์ง๋ง์ ์ธ๋ฏธ์ฝ๋ฅธ์ด ์๊ฒ formatting "useTabs": false, // ํญ์ ์ฌ์ฉ์ ๊ธํ๊ณ ์คํ์ด์ค๋ฐ ์ฌ์ฉ์ผ๋ก ๋์ฒดํ๊ฒ formatting "tabWidth": 2, // ๋ค์ฌ์ฐ๊ธฐ ๋๋น๋ 2์นธ "trailingComma": "all", // ๊ฐ์ฒด๋ ๋ฐฐ์ด ํค:๊ฐ ๋ค์ ํญ์ ์ฝค๋ง๋ฅผ ๋ถํ๋๋ก formatting "printWidth": 80, // ์ฝ๋ ํ์ค์ด maximum 80์นธ "arrowParens": "avoid", // ํ์ดํ ํจ์๊ฐ ํ๋์ ๋งค๊ฐ๋ณ์๋ฅผ ๋ฐ์ ๋ ๊ดํธ๋ฅผ ์๋ตํ๊ฒ formatting "endOfLine": "auto" // EoF ๋ฐฉ์, OS๋ณ๋ก ์ฒ๋ฆฌ ๋ฐฉ์์ด ๋ค๋ฆ }
-
VSCODE ์ต์คํ ์ ์ผ๋ก ์ค์น : ํผ์์ ํธํ๊ฒ ์ค์นํด์ ์ฌ์ฉํ๊ธฐ ์ข์
- ์ค์ : Extension Settings ์์ ์ค์ ๋ณ๊ฒฝ
-
โ๏ธ TDD :
Test Driven Development
-
์ค์ ์ฝ๋๋ฅผ ์์ฑํ๊ธฐ ์ ์ ํ ์คํธ ์ฝ๋๋ฅผ ๋จผ์ ์์ฑ
-
ํ ์คํธ ์ฝ๋๋ฅผ ์์ฑํ ํ ๊ทธ ํ ์คํธ ์ฝ๋๋ฅผ Pass ํ ์ ์๋ ์ค์ ์ฝ๋๋ฅผ ์์ฑ
-
-
โ๏ธ TDD ์ฅ์
-
TDD๋ฅผ ํ๋ฏ๋ก ์ธํด ๋ง์ ๊ธฐ๋ฅ์ ํ ์คํธํ๊ธฐ์
์์ค ์ฝ๋์ ์์ ๊ฐ์ด ๋ถ์ฌ
๋๋ค. -
์ค์ ๊ฐ๋ฐํ๋ฉด์ ๋ง์ ์๊ฐ์ด ์์๋๋ ๋ถ๋ถ์ ๋๋ฒ๊น ๋ถ๋ถ์ด๊ธฐ์ TDD๋ฅผ ์ฌ์ฉํ๋ฉด
๋๋ฒ๊น ์๊ฐ์ด ์ค์ด๋ค๊ณ ์ค์ ๊ฐ๋ฐ ์๊ฐ๋ ์ค์ด
๋ญ๋๋ค. -
์์ค ์ฝ๋ ํ๋ํ๋๋ฅผ ๋์ฑ ์ ์ค
ํ๊ฒ ์งค ์ ์๊ธฐ ๋๋ฌธ์ ๊นจ๋ํ ์ฝ๋๊ฐ ๋์ฌ ํ๋ฅ ์ด ๋์ต๋๋ค.
-
- ๐ฅ
FireEvent API
:์ ์ ๊ฐ ๋ฐ์์ํค๋ ์ก์ (์ด๋ฒคํธ)์ ๋ํ ํ ์คํธ
๋ฅผ ํด์ผํ๋ ๊ฒฝ์ฐ ์ฌ์ฉ - FireEvent API ์ดํด๋ณด๊ธฐ
// App.js
import { useState } from "react";
import "./App.css";
function App() {
const [counter, setCounter] = useState(0);
const [disabled, setDisabled] = useState(false);
return (
<div className="App">
<header className="App-header">
<h3 data-testid="counter">{counter}</h3>
<div>
<button
data-testid="minus-button"
onClick={() => setCounter((count) => count - 1)}
disabled={disabled}
>
-
</button>
<button
data-testid="plus-button"
onClick={() => setCounter((count) => count + 1)}
disabled={disabled}
>
+
</button>
</div>
<div>
<button
data-testid="on/off-button"
style={{ backgroundColor: "blue" }}
onClick={() => setDisabled((prev) => !prev)}
>
on/off
</button>
</div>
</header>
</div>
);
}
export default App;
// App.test.js
import { render, screen, fireEvent } from "@testing-library/react";
import App from "./App";
test("the counter starts at 0", () => {
// App ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋ง
render(<App />);
//screen object๋ฅผ ์ด์ฉํด์ ์ํ๋ ์๋ ๋ฉํธ์ ์ ๊ทผ(์ ๊ทผํ ๋ ID๋ก)
const counterElement = screen.getByTestId("counter");
// id๊ฐ counter์ธ ์๋ ๋ฉํธ์ ํ
์คํธ๊ฐ 0์ธ์ง ํ
์คํธ
expect(counterElement).toHaveTextContent(0);
});
test("minus button has correct text", () => {
// App ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋ง
render(<App />);
//screen object๋ฅผ ์ด์ฉํด์ ์ํ๋ ์๋ ๋ฉํธ์ ์ ๊ทผ(์ ๊ทผํ ๋ ID๋ก)
const minusButtonElement = screen.getByTestId("minus-button");
// id๊ฐ minus-button์ธ ์๋ ๋ฉํธ์ ํ
์คํธ๊ฐ -์ธ์ง ํ
์คํธ
expect(minusButtonElement).toHaveTextContent("-");
});
test("plus button has correct text", () => {
// App ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋ง
render(<App />);
//screen object๋ฅผ ์ด์ฉํด์ ์ํ๋ ์๋ ๋ฉํธ์ ์ ๊ทผ(์ ๊ทผํ ๋ ID๋ก)
const plusButtonElement = screen.getByTestId("plus-button");
// id๊ฐ plus-button์ธ ์๋ ๋ฉํธ์ ํ
์คํธ๊ฐ +์ธ์ง ํ
์คํธ
expect(plusButtonElement).toHaveTextContent("+");
});
test("When the + button is pressed, the counter changes to 1", () => {
// App ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋ง
render(<App />);
//screen object๋ฅผ ์ด์ฉํด์ ์ํ๋ ์๋ ๋ฉํธ์ ์ ๊ทผ(์ ๊ทผํ ๋ ID๋ก)
const buttonElement = screen.getByTestId("plus-button");
// fireEvent๋ ์ ์ ๊ฐ ๋ฐ์์ํค๋ ์ก์
(์ด๋ฒคํธ)์ ๋ํ ํ
์คํธ๋ฅผ ํด์ผํ๋ ๊ฒฝ์ฐ ์ฌ์ฉ
fireEvent.click(buttonElement);
//screen object๋ฅผ ์ด์ฉํด์ ์ํ๋ ์๋ ๋ฉํธ์ ์ ๊ทผ(์ ๊ทผํ ๋ ID๋ก)
const counterElement = screen.getByTestId("counter");
// id๊ฐ counter์ธ ์๋ ๋ฉํธ์ ํ
์คํธ๊ฐ 1์ธ์ง ํ
์คํธ
expect(counterElement).toHaveTextContent(1);
});
test("When the - button is pressed, the counter changes to -1", () => {
// App ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋ง
render(<App />);
//screen object๋ฅผ ์ด์ฉํด์ ์ํ๋ ์๋ ๋ฉํธ์ ์ ๊ทผ(์ ๊ทผํ ๋ ID๋ก)
const buttonElement = screen.getByTestId("minus-button");
// fireEvent๋ ์ ์ ๊ฐ ๋ฐ์์ํค๋ ์ก์
(์ด๋ฒคํธ)์ ๋ํ ํ
์คํธ๋ฅผ ํด์ผํ๋ ๊ฒฝ์ฐ ์ฌ์ฉ
fireEvent.click(buttonElement);
//screen object๋ฅผ ์ด์ฉํด์ ์ํ๋ ์๋ ๋ฉํธ์ ์ ๊ทผ(์ ๊ทผํ ๋ ID๋ก)
const counterElement = screen.getByTestId("counter");
// id๊ฐ counter์ธ ์๋ ๋ฉํธ์ ํ
์คํธ๊ฐ -1์ธ์ง ํ
์คํธ
expect(counterElement).toHaveTextContent(-1);
});
test("on/off button has blue color", () => {
// App ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋ง
render(<App />);
//screen object๋ฅผ ์ด์ฉํด์ ์ํ๋ ์๋ ๋ฉํธ์ ์ ๊ทผ(์ ๊ทผํ ๋ ID๋ก)
const buttonElement = screen.getByTestId("on/off-button");
// on/off ๋ฒํผ color๋ฅผ blue ํ์ธ
expect(buttonElement).toHaveStyle({ backgroundColor: "blue" });
});
test("Prevent the -,+ button from being pressed when the on/off button is cliecked", () => {
// App ์ปดํฌ๋ํธ๋ฅผ ๋ ๋๋ง
render(<App />);
//screen object๋ฅผ ์ด์ฉํด์ ์ํ๋ ์๋ ๋ฉํธ์ ์ ๊ทผ(์ ๊ทผํ ๋ ID๋ก)
const onOffButtonElement = screen.getByTestId("on/off-button");
// fireEvent๋ ์ ์ ๊ฐ ๋ฐ์์ํค๋ ์ก์
(์ด๋ฒคํธ)์ ๋ํ ํ
์คํธ๋ฅผ ํด์ผํ๋ ๊ฒฝ์ฐ ์ฌ์ฉ
fireEvent.click(onOffButtonElement);
//screen object๋ฅผ ์ด์ฉํด์ ์ํ๋ ์๋ ๋ฉํธ์ ์ ๊ทผ(์ ๊ทผํ ๋ ID๋ก)
const plusButtonElement = screen.getByTestId("plus-button");
// on/off-button ํด๋ฆญํ ๋, -, + ๋ฒํผ์ ๋ชป๋๋ฅด๊ฒ ๋ง๊ธฐ
expect(plusButtonElement).toBeDisabled();
});
-
์ด์ ์ ํ ์คํ ์์ ๋ฒํผ์ ํด๋ฆญํ์ ๋ fireEvent API๋ฅผ ์ฌ์ฉํ์ต๋๋ค. ์ด๋ fireEvent๋ฅผ ์ฌ์ฉํด์ ์ ์ฒ๋ฆฌ๋ฅผ ํด์คฌ์ง๋ง userEvent API๋ฅผ ์ฌ์ฉํ๋ ๊ฒ ๋ ์ข์ ๋ฐฉ๋ฒ์ ๋๋ค. fireEvent.click(element) < userEvent.click(element)
-
userEvent
-
userEvent๋ fireEvent ๋ฅผ ์ฌ์ฉํด์ ๋ง๋ค์ด์ก์ต๋๋ค. userEvent์ ๋ด๋ถ ์ฝ๋๋ฅผ ๋ณด๋ฉด fireEvent๋ฅผ ์ฌ์ฉํ๋ฉด์ ์๋ฆฌ๋จผํธ์ ํ์ ์ ๋ฐ๋ผ์ Label์ ํด๋ฆญํ์ ๋, checkbox, radio ์ ํด๋ฆญํ์ ๋ ๊ทธ ์๋ฆฌ๋จผํธ ํ์ ์ ๋ง๋ ๋์ฑ ์ ์ ํ ๋ฐ์์ ๋ณด์ฌ์ค๋๋ค.
-
์๋ฅผ ๋ค์ด์ fireEvent ๋ก ๋ฒํผ์ ํด๋ฆญํ๋ฉด fireEvent.click(button) ๋ฒํผ์ด focus ๋์ง ์์ต๋๋ค. ํ์ง๋ง userEvent๋ก ํด๋ฆญํ๋ฉด userEvent.click(button) ๋ฒํผ์ด focus ๊ฐ ๋ฉ๋๋ค. ์ด๋ ๊ฒ ์ค์ ์ฌ์ฉํ๋ ์ ์ ๊ฐ ๋ณด๊ธฐ์ ์ค์ ๋ฒํผ์ ํด๋ฆญํ๋ ํ์๊ฐ ๋ ์ ํํ๋๊ธฐ์ userEvent๋ฅผ ์ฌ์ฉํ๋ ๊ฒ ๋ ์ถ์ฒ๋๋ ๋ฐฉ๋ฒ์ ๋๋ค.
-