чернетка
на комерції тести переважно не пишуть
тестові програми можуть бути довші ніж сам код
-------
напишемо код програми перевірки , яка перевірятиме фомат символів імені юзера.
в utils створимо userNamesHandler.js
/**
* User name handler function.
* @param {string} name - user name
* @returns {string}
*/
module.exports = (name) => {
if (typeof name !== 'string') return '';
const handledUserNameArray = name
.normalize('NFD')
.replace(/\p{Diacritic}/gu, '')
.toLowerCase()
.replace(/[^a-z]/g, ' ')
.split(' ');
const resultArray = [];
for (const item of handledUserNameArray) {
if (item) resultArray.push(item.charAt(0).toUpperCase() + item.slice(1));
}
return resultArray.join(' ');
};
В коді вище отримується рялок, замінюються діакратичні символи, а також літери всі символи крім латинки після цього розбивається на масив по пробілу.
укінці збільшуємо перший символ, і обїєднуємо масив в рядок через пробіл.
тепер в userServices.js в функції signupUser допишемо такий код.
const userNamesHandler = require("../utils/userNamesHandler")
exports.signupUser = async (userData) => {
const { name, ...restUserData } = userData;
const newUserData = {
...restUserData,
name: userNamesHandler(name),
role: userRolesEnum.USER,
};
const newUser = await User.create(newUserData);
newUser.password = undefined;
const token = signToken(newUser.id);
return { user: newUser, token };
};
тепер при створенні контакта через постмен. нам будуть виправлятися оці неправильні внесені дані
Але нам треба потестити цю функцію.
ставимо пакети в режимі розробника
npm i -D jest supertest
впекедж джсон ставимо скрипт на тес
"test": "jest"
А в папці, де лежить наш код для перевірки (тобто в утілс) створимо папку __test__
ці файди не будуть застосовані в застосунку, а тільки для тестів використовуватися
і за таким само форматом всередині створимо файл userNamesHandler.test.js.
створимо програмку для тестування для перевірки роботи (окремий юніт тест)
// Set test suite.
const calc = (a, b) => a + b;
describe("Test example", () => {
// Set single test
test("test calc sum 2 + 2", () => {
expect(calc(2, 2)).toBe(4);
});
// Set single test
it("should return 5", () => {
expect(calc(2, 3)).toBe(5);
});
});
тут describe - приймає назву тесту і колбек функцію. а в ній команду test (замість test можна писати it("should", ()=>{})), яка першим параметром приймає назву тесту, а другим також кодбек функцію, в якій вписуємо expect (тобто шо робимо) і toBe (тобто що маємо отримати)
щоб запустити тест потрібно в консолі запустити
npm run test
перевіряємо результати тесту в консолі
тепрер напишемо теск кейс для нашого прикдалу перевірки логіна
можна задати масив кейсів і циклом пройтися перевірити всі кейси
аде також можна писати тес і окремо під кожен окремий кейс.
const userNameHandler = require("../userNamesHandler");
const testingData = [
{ input: "Jimi Hendrix", output: "Jimi Hendrix" },
{ input: "jimi hendrix", output: "Jimi Hendrix" },
{ input: "jimi Hendrix", output: "Jimi Hendrix" },
{ input: " Jimi hendriX ", output: "Jimi Hendrix" },
{ input: "Jimi_Hendrix", output: "Jimi Hendrix" },
{ input: "jimi.hendrix", output: "Jimi Hendrix" },
{ input: "jimi@hend@rix", output: "Jimi Hend Rix" },
{ input: "_jimi * hendrix", output: "Jimi Hendrix" },
{ input: "jimi hèndrix__", output: "Jimi Hendrix" },
{ input: "jimi中村hèndrix__", output: "Jimi Hendrix" },
{ input: "jimi de Hèndrix__", output: "Jimi De Hendrix" },
{ input: "中村哲二", output: "" },
{ input: undefined, output: "" },
{ input: null, output: "" },
{ input: true, output: "" },
];
describe("User names handler tests", () => {
it("should returns Jimi Hendrix", () => {
expect(userNameHandler(testingData[0].input)).toBe(testingData[0].output);
});
test("test all user name cases", () => {
for (const item of testingData) {
const normalizedName = userNameHandler(item.input);
expect(normalizedName).toBe(item.output);
}
});
});
Тут ми перебираємо циклом варіанти і якщо хоч один тест не виконається, то в консолі буде помилка
Тепер напишемо тест на цілий роут логіна
спочатку в індекс файлі експортнемо наз запуск сервера
// ===========SERVER INIT=========== //
module.exports = app.listen(3000, () => {
console.log("server is up and runned on port 3000");
});
Відповідно у папці контролерів створюємо папку __test__ і в ній файл який будемо тестувати authController.test.js
const request = require("supertest");
const app = require("../../index");
describe("POST /auth/login", () => {
beforeAll(() => {
console.log("before all");
});
beforeEach(() => {
console.log("before each");
});
afterEach(() => {
console.log("after each");
});
afterAll(() => {
console.log("after all");
});
it("should return user object and jwt", async () => {
const testData = {
email: "khomiak3@gmail.com",
password: "Password1234$",
};
const res = await request(app).post("/auth/login").send(testData);
expect(res.statusCode).toBe(200);
expect(res.body).toEqual(
expect.objectContaining({
token: expect.any(String),
user: expect.any(Object),
})
);
});
it("should return unauth error", async () => {
const testData = {
email: "khomiak3@gmail.com",
password: "Password1234$",
};
const res = await request(app).post("/auth/login").send(testData);
expect(res.statusCode).toBe(401);
});
it("should return unauth error", async () => {
const testData = {
email: "khomiak3@gmail.com",
};
const res = await request(app).post("/auth/login").send(testData);
expect(res.statusCode).toBe(401);
});
});
розберемо той код. спочатку підключення імітатора запитів, а потім імпорт підключення самого сервера
beforeAll, beforeEach, afterEach, afterAll - це хуки в які можна прописувати різний функціонал
при запуску тесту перевірятимуться всі умови тесту
ТЕМПЛЕЙТ ДВІЖКИ (ЩАБЛОНІЗАТОРИ)
приклад шаблонізатора
https://pugjs.org/api/getting-started.html
Розглянемо на прикладі паг
підключаються по-ріщному
можна в індекс фпйлі його підключити перед пілключенням до бази даних
app.set('view engine', 'pug');
app.set('views', path.join(__dirname, 'views'));
перший рядок підключення паг
другий рядок вказання папки де лежатимуть темплейти
відтак в корені кадалога створимо папку views
а в ньому підпапку layouts а вде у ній файл main.pug
Зашоблонізуємо в ньому html-файл
І цьому випадку закриваючі теги не потрібні, а вкладеність визначається табудяцією. стидізацію там де цсс будемо брати зі статікс, який ми щаримо назовні для всіх користувачів
у шаблонізаторах можна передавати змінні
подивимося яуий вигляд матиме файл main.pug
doctype html
html(lang="en")
head
meta(charset="UTF-8")
meta(name="viewport" content="width=device-width, initial-scale=1.0")
title #{title}
link(rel="stylesheet" href="/css/main.css")
body
header.header
nav.header__nav
ul.header__item-list
li.header__item
a(href="/" class=(active === 'home' ? 'active' : '')) Home
li.header__item
a(href="/todos" class=(active === 'todos' ? 'active' : '')) Todos List
main.main
block content
footer.footer
.footer__info
.footer__copy All rights reserved ©
.footer__year 2023
можна використати плагін для vc beautify pug. він правиль чистить пробіли зайві і виставляє коректно табуляцію.
створимо додатково два файли home.pug і todos.pug
extends layouts/main
block content
h1 TODO APP!!
p This our super hyper project!!
тут вказуємо що будемо вставляти дані в layouts/main а нижче вказуємо назва блоку і сам контент
extends layouts/main
block content
h1 Todos list
.todos
each todo in todos
.todo
.owner
figure.owner__pic
img(src= todo.owner.avatar)
p.owner__name= todo.owner.name
.todo__content
h3.h3= todo.title
p.description= todo.description
p.duedate= todo.due.toLocaleString('uk-UA')
примітно, що якшо зочемо передати змінну то ставимо дорівн.є, а інакше це буде передаватися текст
Шаблони творені і тепер їх треба роздати . завдяки окремим роутам. а підключаємо в індекс файлі де всі роути
const viewRoutes = require('./routes/viewRoutes');
app.use('/', viewRoutes);
тепер пропишемо сам роут (ці роути будуть просто передавати на фронт шаблони з певними даними)
const { Router } = require('express');
const viewController = require('../controllers/viewController');
const router = Router();
router.get('/', viewController.home);
router.get('/todos', viewController.todos);
module.exports = router;
також напищемо контролер
const Todo = require('../models/todoModel');
const { catchAsync } = require('../utils');
exports.home = (req, res) => {
res.status(200).render('home', {
title: 'Todos Home',
active: 'home',
});
};
exports.todos = catchAsync(async (req, res) => {
const todos = await Todo.find().populate('owner');
res.status(200).render('todos', {
title: 'Todos List',
todos,
active: 'todos',
});
});
По суті це інструкція як з бекенду роздати фронтенд
щоб перевірити треба запустити сервер і пройти на http://localhost:3000/
але видалити раніще створений index.html або перейменувати його. і нам підвантажиться уся наща прописана логіка
Утім в індекс файлі може дублюватися і тому в рядках роуту в індекс пишуть rest-api в роутах, зоб не було збігів з тими роутами які ми роздаємо на зовні через браузер
на фронті після створення реакту це вже використовується досить рідко. переважно використовують для імейлів
Last updated