diff --git a/package-lock.json b/package-lock.json index 4fcb107..65f372c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ }, "devDependencies": { "@playwright/test": "^1.57.0", + "@types/node": "^25.1.0", "allure-playwright": "^3.4.5", "typescript": "^5.9.3" } @@ -33,6 +34,16 @@ "node": ">=18" } }, + "node_modules/@types/node": { + "version": "25.1.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.1.0.tgz", + "integrity": "sha512-t7frlewr6+cbx+9Ohpl0NOTKXZNV9xHRmNOvql47BFJKcEG1CxtxlPEEe+gR9uhVWM4DwhnvTF110mIL4yP9RA==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, "node_modules/allure-js-commons": { "version": "3.4.5", "resolved": "https://registry.npmjs.org/allure-js-commons/-/allure-js-commons-3.4.5.tgz", @@ -442,6 +453,13 @@ "engines": { "node": ">=14.17" } + }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true, + "license": "MIT" } } } diff --git a/package.json b/package.json index aefef72..e06aac2 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "type": "commonjs", "devDependencies": { "@playwright/test": "^1.57.0", + "@types/node": "^25.1.0", "allure-playwright": "^3.4.5", "typescript": "^5.9.3" }, diff --git a/temp/user.json b/temp/user.json new file mode 100644 index 0000000..2bf7790 --- /dev/null +++ b/temp/user.json @@ -0,0 +1 @@ +{"email":"testuser1769775617223@virgilian.com","password":"!Test123456","mailToken":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJpYXQiOjE3Njk3NzU2MTgsInJvbGVzIjpbIlJPTEVfVVNFUiJdLCJhZGRyZXNzIjoidGVzdHVzZXIxNzY5Nzc1NjE3MjIzQHZpcmdpbGlhbi5jb20iLCJpZCI6IjY5N2NhMjAxM2ExZjhmNWE1MDA3MTEyNSIsIm1lcmN1cmUiOnsic3Vic2NyaWJlIjpbIi9hY2NvdW50cy82OTdjYTIwMTNhMWY4ZjVhNTAwNzExMjUiXX19.t8gDCA6xtLYnAex_f3OYj5aYJgls4g8IQs2K37gc6HiqdaKkZveB1ckB31_hhYJag23Ekdi6RW9CNm0RCLsDDQ"} \ No newline at end of file diff --git a/tests/api/registration/register-applicant.api.spec.ts b/tests/api/registration/register-applicant.api.spec.ts index c2f688e..3d69155 100644 --- a/tests/api/registration/register-applicant.api.spec.ts +++ b/tests/api/registration/register-applicant.api.spec.ts @@ -1,4 +1,5 @@ import { test, expect } from '@playwright/test'; +import fs from 'fs'; import axios from 'axios'; import { createTempEmail, @@ -41,6 +42,13 @@ test('API: регистрация абитуриента + подтвержде const registerRes = await axios.post(`${BASE_URL}/auth/register`, registerPayload); expect(registerRes.status).toBe(201); + fs.writeFileSync('temp/user.json', JSON.stringify({ + email, + password: '!Test123456', + mailToken + })); + + const userId = registerRes.data.id; console.log('🆔 ID зарегистрированного пользователя:', userId); @@ -50,7 +58,7 @@ test('API: регистрация абитуриента + подтвержде } console.log('📬 Ожидание письма с кодом подтверждения...'); - const code = await waitForConfirmationCode(mailToken, 60000); + const code = await waitForConfirmationCode(email, mailToken, 'register', 60000); console.log('✅ Код получен:', code); const confirmPayload = { diff --git a/tests/api/registration/register-graduate.api.spec.ts b/tests/api/registration/register-graduate.api.spec.ts index 7a6fd8d..ac6840b 100644 --- a/tests/api/registration/register-graduate.api.spec.ts +++ b/tests/api/registration/register-graduate.api.spec.ts @@ -50,7 +50,7 @@ test('API: регистрация выпускника + подтвержден } console.log('📬 Ожидание письма с кодом подтверждения...'); - const code = await waitForConfirmationCode(mailToken, 60000); + const code = await waitForConfirmationCode(email, mailToken, 'register', 60000); console.log('✅ Код получен:', code); const confirmPayload = { diff --git a/tests/api/registration/register-organization.api.spec.ts b/tests/api/registration/register-organization.api.spec.ts index 7d8a028..5bfd004 100644 --- a/tests/api/registration/register-organization.api.spec.ts +++ b/tests/api/registration/register-organization.api.spec.ts @@ -66,7 +66,7 @@ test('API: регистрация организации + подтвержде } console.log('📬 Ожидание письма с кодом подтверждения...'); - const code = await waitForConfirmationCode(mailToken, 60000); + const code = await waitForConfirmationCode(email, mailToken, 'register',60000); console.log('✅ Код получен:', code); const confirmPayload = { diff --git a/tests/ui/auth/recover-password.spec.ts b/tests/ui/auth/recover-password.spec.ts new file mode 100644 index 0000000..d119868 --- /dev/null +++ b/tests/ui/auth/recover-password.spec.ts @@ -0,0 +1,44 @@ +import { test, expect } from '@playwright/test'; +import { LoginPage } from '../../../page-objects/LoginPage'; +import fs from 'fs'; +import { + waitForConfirmationCode +} from '../../../utils/mailTmApi'; + +test('UI: восстановление пароля', async ({ page }) => { + // Загружаем email пользователя из файла temp/user.json + const loginPage = new LoginPage(page); + const user = JSON.parse(fs.readFileSync('temp/user.json', 'utf-8')); + const newPassword = '!Test12345678'; + + // Переход на главную + await loginPage.goto(); + + // Нажимаем "Забыли пароль?" + await page.getByText('Забыли пароль?').click(); + await expect(page).toHaveURL(/.*confirmation-code/); + + // Вводим почту + await page.fill('input[name="email"]', user.email); + await page.getByRole('button', { name: 'Далее' }).click(); + + // Получаем код из почты + const code = await waitForConfirmationCode(user.email, user.mailToken, 'recover'); + expect(code).toMatch(/^\d{6}$/); + console.log('✅ Код получен:', code); + // Вводим код + await page.fill('input[name="code"]', code); + await page.getByRole('button', { name: 'Далее' }).click(); + + // Вводим новый пароль + await page.fill('input[name="password"]', newPassword); + await page.fill('input[name="passwordRepeat"]', newPassword); + await page.getByRole('button', { name: 'Далее' }).click(); + + // Проверяем успешную авторизацию + await expect(page).toHaveURL(/.*\/account\/profile/); + + // (необязательно) обновляем сохранённый пароль + //user.password = newPassword; + //fs.writeFileSync('temp/user.json', JSON.stringify(user)); +}); diff --git a/tests/ui/registration/register-applicant.spec.ts b/tests/ui/registration/register-applicant.spec.ts index ddc0f8a..32abaf9 100644 --- a/tests/ui/registration/register-applicant.spec.ts +++ b/tests/ui/registration/register-applicant.spec.ts @@ -44,7 +44,7 @@ test('Полная регистрация абитуриента с подтве await registerPage.submit(); await expect(page).toHaveURL(/confirmation-code/); - const code = await waitForConfirmationCode(token, 60000); + const code = await waitForConfirmationCode(email, token, 'register', 60000); await page.fill('input[name="code"]', code); await page.click('button.RecoverPassword_button__5QDxM'); diff --git a/tests/ui/registration/register-graduate.spec.ts b/tests/ui/registration/register-graduate.spec.ts index f733367..717c553 100644 --- a/tests/ui/registration/register-graduate.spec.ts +++ b/tests/ui/registration/register-graduate.spec.ts @@ -46,7 +46,7 @@ test('Полная регистрация выпускника с подтвер await page.waitForTimeout(5000); await expect(page).toHaveURL(/confirmation-code/); - const code = await waitForConfirmationCode(token, 60000); + const code = await waitForConfirmationCode(email, token, 'register', 60000); await page.fill('input[name="code"]', code); await page.click('button.RecoverPassword_button__5QDxM'); diff --git a/tests/ui/registration/register-organization.spec.ts b/tests/ui/registration/register-organization.spec.ts index a68c3c9..3d38aab 100644 --- a/tests/ui/registration/register-organization.spec.ts +++ b/tests/ui/registration/register-organization.spec.ts @@ -78,7 +78,7 @@ test('Полная регистрация организации с подтве await registerPage.submitGeneral(); await expect(page).toHaveURL(/confirmation-code/); - const code = await waitForConfirmationCode(token, 60000); + const code = await waitForConfirmationCode(email, token, 'register', 60000); await page.fill('input[name="code"]', code); await page.click('button.RecoverPassword_button__5QDxM'); diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..673aeb8 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "module": "ESNext", + "target": "ESNext", + "verbatimModuleSyntax": false, + "moduleResolution": "bundler", + "types": ["node", "playwright"], + "lib": ["esnext"], + "strict": true + } +} diff --git a/utils/mailTmApi.ts b/utils/mailTmApi.ts index c610a29..b75f555 100644 --- a/utils/mailTmApi.ts +++ b/utils/mailTmApi.ts @@ -32,7 +32,8 @@ export async function createTempEmail() { } -export async function waitForConfirmationCode(token: string, timeout = 60000) { +export async function waitForConfirmationCode(email: string, token: string, type: 'register' | 'recover', timeout = 60000) { + console.log('📧 Ожидаем код для:', email); const start = Date.now(); while (Date.now() - start < timeout) { @@ -42,33 +43,49 @@ export async function waitForConfirmationCode(token: string, timeout = 60000) { const messages = res.data['hydra:member']; - // ✅ Логируем полученные письма if (messages.length === 0) { console.log('⏳ Письма пока не пришли...'); } else { console.log(`📬 Получено ${messages.length} писем:`); - } - - for (const message of messages) { - console.log('🔖 Тема письма:', message.subject); - - const msg = await axios.get(`${MAIL_TM_BASE}/messages/${message.id}`, { - headers: { Authorization: `Bearer ${token}` }, - }); - - const body = msg.data.text || msg.data.html; - console.log('📩 Тело письма:', body); - - const match = body.match(/\b\d{6}\b/); - if (match) { - console.log('✅ Код подтверждения найден:', match[0]); - return match[0]; + for (const m of messages) { + console.log(`🧾 Письмо: id=${m.id}, тема="${m.subject}"`); } } - await new Promise(res => setTimeout(res, 2000)); // Пауза 2 сек +for (const message of messages) { + console.log('🔖 Тема письма:', message.subject); + + // 🔴 ФИЛЬТРАЦИЯ ЗДЕСЬ + if ( + type === 'register' && + !message.subject.toLowerCase().includes('подтверж') + ) { + continue; + } + + if ( + type === 'recover' && + !message.subject.toLowerCase().includes('сброс') + ) { + continue; + } + + // ⬇️ ТОЛЬКО НУЖНОЕ ПИСЬМО ДОХОДИТ СЮДА + const msg = await axios.get(`${MAIL_TM_BASE}/messages/${message.id}`, { + headers: { Authorization: `Bearer ${token}` }, + }); + + const body = msg.data.text || msg.data.html; + const match = body.match(/\b\d{6}\b/); + + if (match) { + console.log('✅ Код найден:', match[0]); + return match[0]; + } +} + + await new Promise(res => setTimeout(res, 2000)); } throw new Error('Код подтверждения не получен'); -} - +} \ No newline at end of file