test and eslint

ts-jest#

توسط این پکیج می توان برای کامپوننت های react ک با type script نوشته شده اند، تست نوشت ک به صورت زیر می توان در اپلیکیشن reactیی خود آن را نصب کرد:

ts-jest

yarn add jest typescript ts-jest @types/jest -D

سپس توسط کد زیر می توان فایل کانفیگ آن را به پروژه اضافه کرد:

npx ts-jest config:init

حال باید به package.json کد زیر را اضافه کنیم:

{
"scripts": {
"test": "jest"
}
}

برای ساخت فایل تست برای هر کامپوننت باید بعد از نام آن از کلمه spec یا test استفاده کنیم، مثل : sum.spec.ts یا sum.test.ts

// sum.ts
export const sum = (a: number, b: number) => {
return a + b
}
// sum.spec.ts
import { sum } from './sum';
it("Summing 5 and 2 will return 7", ()=> {
expect(sum(5, 2)).toBe(7)
})

سپس برای استفاده از متد های از پیش ساخته شده برای تست در react می توان از پکیج react testing library استفاده کنیم:

react testing library

yarn add @testing-library/react @testing-library/user-event @testing-library/dom @testing-library/jest-dom -D

حال برای اینکه کامپوننت های react ک همراه با spec.tsx.* هستند نیاز است تا یک فایل به نام tsconfig.jest.json بسازیم و کد های زیر را در آن قرار دهیم:

{
"extends": "./tsconfig.json",
"compilerOptions": {
"jsx": "react-jsx"
}
}

سپس نیاز است ک فایل jest.config.ts را نیز تغییر دهیم:

module.exports = {
// [...]
testEnvironment: 'jsdom', // برای اجرا شدن تست ها باید این قسمت را نیز تغییر دهیم
globals: {
'ts-jest': {
tsconfig: './tsconfig.jest.json'
}
}
}

برای اینکه توابعی مانند 2 تابع زیر را بتوان در تست ها استفاده کرد باید یک کانفیگ جدید را ب پروژه اضافه کرد، در واقع توسط این کانفیگ یک سری از کدهای تست ما قبل از اجرا شدن مابقی کد ها اجرا می شود و به ما اجازه این را میدهد ک از توابع زیر استفاده کنیم:

import {render, screen} from "@testing-library/react";
import { Hello } from "./Hello";
it("rendres 'Hello world'", () => {
render(<Hello/>);
const myElem = screen.getByText("/Hello World/");
expect(myElem).toBeInTheDocument();
})

از آدرس زیر باید کانفیگ آن را برداریم و به jest.config.js اضافه کنیم:

jest-setupFilesAfterEnv

module.exports = {
setupFilesAfterEnv: ['./jest.setup.ts']
};

حال باید یک فایل دیگر ب نام jest.setup.ts را مسیر src یا مسیر test اضافه کنیم:

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

eslint#

همچنین می توان از eslint نیز همراه با jest استفاده کرد ک خیلی در جلوگیری از باگ ها کمک می کند.

برای اینکار باید ابتدا eslint خود پروژه را ( در صورت وجود ) نامش را عوض کنیم ( تا از محتوای آن در eslint جدید استفاده کنیم ) و سپس از دستور زیر استفاده میکنیم:

npx eslint --init

حال در فایل جدید از کد های زیر استفاده میکنیم:

// .eslintrc.ts
module.exports = {
"extends": [
"eslint:recommended",
"plugin:react/recommended",
"plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/recommended-requiring-type-checking",
"next",
"next/core-web-vitals"
],
"parser": "@typescript-eslint/parser",
"parserOptions": {
project: ["./tsconfig.eslint.json"], // Specify it only for TypeScript files
"ecmaFeatures": {
"jsx": true
},
"ecmaVersion": 13,
"sourceType": "module"
},
"rules": { // در این قسمت هر قانونی را می توانیم برای لینت قرار دهیم
"@typescript-eslint/explicit-module-boundary-types": "off" // برای غیر فعال سازی گیر دادن به تایپ های تمامی فانکشن ها
"@typescript-eslint/no-explicit-any": "off",
"@typescript-eslint/ban-ts-comment": "off",
"@typescript-eslint/no-var-requires": "off",
"@typescript-eslint/prefer-nullish-coalescing": "error",
}
};

✨ ممکن است بعد نصب eslint و jest در react به اروری مبنی بر اینکه ورژن این 2 پکیج بالا تر از پکیج های نصب شده در این اپلیکیشن می باشد ک در آن صورت باید package-lock.json و yarn.lock و node_modules را حذف کنیم و هم چنین از package.json نیز باید نام این 2 پکیج را نیز حذف کنیم و دوباره npm i یا yarn بزنیم.

همچنین چون ما فولدر اصلی pages در next را به src جابه جا کردیم، باید توسط دستور زیر ( فقط برای next ) مسیری ک eslint چک میکند را تغییر دهیم ( package.json ):

next-lint

{
"scripts": {
"lint": "next lint --dir src"
}
}

حال باید پلاگین هایی ک نیاز داریم برای متصل کردن eslint و jest را نصب و آن را به فایل .eslintrc.js در قسمت extends، اضافه کنیم:

eslint-plugin-jest

yarn add eslint-plugin-jest -D
// .eslintrc.js
module.exports = {
"extends": [
"eslint:recommended",
"plugin:react/recommended",
"plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/recommended-requiring-type-checking",
+ "plugin:jest/recommended",
+ "plugin:jest/style",
"next",
"next/core-web-vitals"
]
};

سپس باید پلاگینی ک مربوط به testing library می باشد را برای eslint نصب کنیم:

eslint-plugin-testing-library

yarn add eslint-plugin-testing-library -D
// .eslintrc.js
module.exports = {
"extends": [
"eslint:recommended",
"plugin:react/recommended",
"plugin:@typescript-eslint/recommended",
"plugin:@typescript-eslint/recommended-requiring-type-checking",
"plugin:jest/recommended",
"plugin:jest/style",
+ "plugin:testing-library/react",
"next",
"next/core-web-vitals"
]
};

lint-staged#

گاهی اوقات ما نیاز داریم ک کد های ما از نظر ساختاری، تمیز بشوند و اگر اروری دارد، هنگام کامیت کردن، ب ما نشان دهد، یعنی یک script قبل از commit اجرا می شود و مواردی ک ما ب آن گفته ایم را برای ما انجام می دهد

npx mrm@2 lint-staged

این پکیج، 2 پیش نیاز دارد و باید آن ها را نیز نصب کنیم:

yarn add lint-staged prettier -D

حال باید در فولدری ک نام آن husky. می باشد، در فایل pre-commit، کامند اصلی آن را به کامند زیر تغییر بدهیم:

npm run lint-staged

حال باید این دستور را نیز در package.json نیز قرار دهیم تا هنگام اجرا ب مشکل بر نخورد:

{
"scripts": {
"lint-staged": "lint-staged"
}
}

همچنین اگر از ts و tsx بجای js و jsx استفاده میکنیم، باید در قسمت انتهایی package.json، تغییراتی اعمال کنیم:

{
"lint-staged": {
"*.(tsx|ts)": "eslint --cache --fix",
"*": "prettier --write --ignore-unknown"
}
}

coverage#

حال برای اینکه تست در حالت ci را نیز اضافه کنیم باید از کد های زیر در jest.config.js استفاده کنیم

jest-coveragethreshold

// jest.config.js
module.exports = {
//...
coverageThreshold: {
global: {
branches: 100,
functions: 100,
lines: 100,
statements: 100
}
}
}

حال برای اینکه این قسمت هم ب درستی کار کند، باید در package.json دستور زیر را اضافه کنیم:

{
"scripts": {
"test:ci": "jest --coverage --silent --ci",
"prepare": "husky install",
"lint-staged": "lint-staged"
}
}

🎉🎉🎉 حتما باید تمام فایل ها ( اگر از ts استفاده می شود ) حتما با پسوند های ts و tsx باشد، حتی eslint.، babel.config و ...، زیرا ب ما ارور parserOption میدهد ک مربوط ب مغایرت داشتن فرمت فایل ها می باشد.

🎉 تغییرات زیر نیز باید اعمال شود روی فایل های مورد نظر یا اگر وجود ندارد، باید ساخته شوند:

tsconfig.json

{
"include": ["src", "./jest.config.ts", ".eslintrc", "./babel.config"]
}

tsconfig.eslint.json

{
"extends": "./tsconfig.json",
"include": ["babel.config"]
}

github action ( optional )#

حال میتوان وارد repo خود شویم و در قسمت actions یک workflow جدید برای node بسازیم

سپس کد های درون آن را به کد های زیر تغییر دهیم:

name: Node.js CI
on:
push:
branches: [ main ]
pull_request:
branches: "*"
jobs:
build:
runs-on: ${{matrix.os}}
strategy:
matrix:
node-version: [12.x, 14.x, 16.x]
os: [ubuntu-latest, windows-latest, macos-latest]
steps:
- uses: actions/checkout@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v2
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- run: npm i -g npm@latest # این خط کد را اگر ب ارور خوردیم در حالت عادی، اضافه میکنیم
- run: npm ci
- run: npm run lint
- run: npm run test:ci

حال میتوان کد هایمان را به repo مورد نظرمان push کنیم.