ci-tests-frontend-e2e-fix
Some checks failed
Deploy on push / deploy (push) Has been cancelled

This commit is contained in:
2025-08-12 14:45:59 +03:00
parent ba2cbe25d2
commit 81b2ec41fa
8 changed files with 88 additions and 66 deletions

View File

@@ -41,15 +41,6 @@ jobs:
run: | run: |
npm run build npm run build
- name: Start Frontend Server
run: |
# Запускаем фронтенд сервер в фоне
npm run dev &
# Ждем запуска сервера
sleep 10
# Проверяем что сервер запустился
curl -f http://localhost:3000 || exit 1
- name: Setup Playwright (use pre-installed browsers) - name: Setup Playwright (use pre-installed browsers)
env: env:
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1

View File

@@ -1,5 +1,6 @@
import pytest import pytest
PORT = 8000
@pytest.fixture @pytest.fixture
def oauth_settings() -> dict[str, dict[str, str]]: def oauth_settings() -> dict[str, dict[str, str]]:
@@ -14,7 +15,7 @@ def oauth_settings() -> dict[str, dict[str, str]]:
@pytest.fixture @pytest.fixture
def frontend_url() -> str: def frontend_url() -> str:
"""URL фронтенда для тестов""" """URL фронтенда для тестов"""
return "https://localhost:3000" return f"https://localhost:{PORT}"
@pytest.fixture(autouse=True) @pytest.fixture(autouse=True)

View File

@@ -1,7 +1,5 @@
"""Тестовые настройки для OAuth""" """Тестовые настройки для OAuth"""
FRONTEND_URL = "https://localhost:3000"
OAUTH_CLIENTS = { OAUTH_CLIENTS = {
"GOOGLE": {"id": "test_google_id", "key": "test_google_secret"}, "GOOGLE": {"id": "test_google_id", "key": "test_google_secret"},
"GITHUB": {"id": "test_github_id", "key": "test_github_secret"}, "GITHUB": {"id": "test_github_id", "key": "test_github_secret"},

View File

@@ -20,7 +20,9 @@ async def check_communities_table():
try: try:
# В CI/CD фронтенд обслуживается бэкендом на порту 8000 # В CI/CD фронтенд обслуживается бэкендом на порту 8000
frontend_url = "http://localhost:3000" # В локальной разработке - на порту 3000
is_ci = os.getenv("PLAYWRIGHT_HEADLESS", "false").lower() == "true"
frontend_url = "http://localhost:8000" if is_ci else "http://localhost:3000"
print(f"🌐 Открываем админ-панель на {frontend_url}...") print(f"🌐 Открываем админ-панель на {frontend_url}...")
await page.goto(frontend_url) await page.goto(frontend_url)
await page.wait_for_load_state("networkidle") await page.wait_for_load_state("networkidle")

View File

@@ -1,4 +1,6 @@
import pytest import pytest
import os
from settings import FRONTEND_URL
from sqlalchemy import create_engine from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker from sqlalchemy.orm import sessionmaker
from sqlalchemy.pool import StaticPool from sqlalchemy.pool import StaticPool
@@ -486,3 +488,14 @@ def cleanup_test_data(db_session, user_ids=None, community_ids=None):
db_session.query(CommunityAuthor).where(CommunityAuthor.community_id.in_(community_ids)).delete(synchronize_session=False) db_session.query(CommunityAuthor).where(CommunityAuthor.community_id.in_(community_ids)).delete(synchronize_session=False)
db_session.commit() db_session.commit()
@pytest.fixture
def frontend_url() -> str:
"""URL фронтенда для тестов"""
# В CI/CD используем порт 8000 (бэкенд), в локальной разработке - порт 3000
is_ci = os.getenv("PLAYWRIGHT_HEADLESS", "false").lower() == "true"
if is_ci:
return "http://localhost:8000"
else:
return FRONTEND_URL

View File

@@ -94,7 +94,7 @@ class TestCommunityDeleteE2EBrowser:
# Проверяем фронтенд # Проверяем фронтенд
try: try:
response = requests.get("http://localhost:3000", timeout=2) response = requests.get("http://localhost:8000", timeout=2)
if response.status_code == 200: if response.status_code == 200:
print("✅ Фронтенд сервер уже запущен") print("✅ Фронтенд сервер уже запущен")
frontend_running = True frontend_running = True
@@ -104,45 +104,64 @@ class TestCommunityDeleteE2EBrowser:
frontend_running = False frontend_running = False
if not frontend_running: if not frontend_running:
# В CI/CD фронтенд сервер запускается в workflow # Проверяем, находимся ли мы в CI/CD окружении
# В локальной разработке запускаем фронтенд сервер is_ci = os.getenv("PLAYWRIGHT_HEADLESS", "false").lower() == "true"
print("🔄 Запускаем фронтенд сервер...")
try:
frontend_process = subprocess.Popen(
["npm", "run", "dev"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
cwd=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
)
# Ждем запуска фронтенда if is_ci:
print("⏳ Ждем запуска фронтенда...") print("🔧 CI/CD окружение - фронтенд собран и обслуживается бэкендом")
for i in range(15): # Ждем максимум 15 секунд # В CI/CD фронтенд уже собран и обслуживается бэкендом на порту 8000
try: try:
response = requests.get("http://localhost:3000", timeout=2) response = requests.get("http://localhost:8000/", timeout=2)
if response.status_code == 200: if response.status_code == 200:
print("Фронтенд сервер запущен") print("Бэкенд готов обслуживать фронтенд")
break frontend_running = True
except: frontend_process = None
pass else:
await asyncio.sleep(1) print(f"⚠️ Бэкенд вернул статус {response.status_code}")
else: frontend_process = None
# Если фронтенд не запустился, выводим логи except Exception as e:
print("❌ Фронтенд сервер не запустился за 15 секунд") print(f"⚠️ Не удалось проверить бэкенд: {e}")
# Получаем логи процесса
if frontend_process:
stdout, stderr = frontend_process.communicate()
print(f"📋 STDOUT: {stdout.decode()}")
print(f"📋 STDERR: {stderr.decode()}")
print("⚠️ Продолжаем тест без фронтенда (только API тесты)")
frontend_process = None frontend_process = None
else:
# Локальная разработка - запускаем фронтенд сервер
print("🔄 Запускаем фронтенд сервер...")
try:
frontend_process = subprocess.Popen(
["npm", "run", "dev"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
cwd=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
)
except Exception as e: # Ждем запуска фронтенда
print(f"⚠️ Не удалось запустить фронтенд сервер: {e}") print("⏳ Ждем запуска фронтенда...")
print("🔄 Продолжаем тест без фронтенда (только API тесты)") for i in range(15): # Ждем максимум 15 секунд
frontend_process = None try:
# В локальной разработке фронтенд работает на порту 3000
response = requests.get("http://localhost:3000", timeout=2)
if response.status_code == 200:
print("✅ Фронтенд сервер запущен")
break
except:
pass
await asyncio.sleep(1)
else:
# Если фронтенд не запустился, выводим логи
print("❌ Фронтенд сервер не запустился за 15 секунд")
# Получаем логи процесса
if frontend_process:
stdout, stderr = frontend_process.communicate()
print(f"📋 STDOUT: {stdout.decode()}")
print(f"📋 STDERR: {stderr.decode()}")
print("⚠️ Продолжаем тест без фронтенда (только API тесты)")
frontend_process = None
except Exception as e:
print(f"⚠️ Не удалось запустить фронтенд сервер: {e}")
print("🔄 Продолжаем тест без фронтенда (только API тесты)")
frontend_process = None
# Запускаем браузер # Запускаем браузер
print("🔄 Запускаем браузер...") print("🔄 Запускаем браузер...")
@@ -223,7 +242,7 @@ class TestCommunityDeleteE2EBrowser:
return user return user
async def test_community_delete_browser_workflow(self, browser_setup, test_users): async def test_community_delete_browser_workflow(self, browser_setup, test_users, frontend_url):
"""Полный E2E тест удаления сообщества через браузер""" """Полный E2E тест удаления сообщества через браузер"""
page = browser_setup["page"] page = browser_setup["page"]
@@ -240,8 +259,6 @@ class TestCommunityDeleteE2EBrowser:
try: try:
# 1. Открываем админ-панель # 1. Открываем админ-панель
# В CI/CD фронтенд обслуживается бэкендом на порту 8000
frontend_url = "http://localhost:3000"
print(f"🌐 Открываем админ-панель на {frontend_url}...") print(f"🌐 Открываем админ-панель на {frontend_url}...")
await page.goto(frontend_url) await page.goto(frontend_url)
@@ -591,7 +608,7 @@ class TestCommunityDeleteE2EBrowser:
raise raise
async def test_community_delete_without_permissions_browser(self, browser_setup, test_community_for_browser): async def test_community_delete_without_permissions_browser(self, browser_setup, test_community_for_browser, frontend_url):
"""Тест попытки удаления без прав через браузер""" """Тест попытки удаления без прав через браузер"""
page = browser_setup["page"] page = browser_setup["page"]
@@ -599,7 +616,7 @@ class TestCommunityDeleteE2EBrowser:
try: try:
# 1. Открываем админ-панель # 1. Открываем админ-панель
print("🔄 Открываем админ-панель...") print("🔄 Открываем админ-панель...")
await page.goto("http://localhost:3000/admin") await page.goto(f"{frontend_url}/admin")
await page.wait_for_load_state("networkidle") await page.wait_for_load_state("networkidle")
# 2. Авторизуемся как обычный пользователь (без прав admin) # 2. Авторизуемся как обычный пользователь (без прав admin)
@@ -675,7 +692,7 @@ class TestCommunityDeleteE2EBrowser:
print(f"❌ Ошибка в E2E тесте прав доступа: {e}") print(f"❌ Ошибка в E2E тесте прав доступа: {e}")
raise raise
async def test_community_delete_ui_validation(self, browser_setup, test_community_for_browser, admin_user_for_browser): async def test_community_delete_ui_validation(self, browser_setup, test_community_for_browser, admin_user_for_browser, frontend_url):
"""Тест UI валидации при удалении сообщества""" """Тест UI валидации при удалении сообщества"""
page = browser_setup["page"] page = browser_setup["page"]
@@ -683,7 +700,7 @@ class TestCommunityDeleteE2EBrowser:
try: try:
# 1. Авторизуемся как админ # 1. Авторизуемся как админ
print("🔐 Авторизуемся как админ...") print("🔐 Авторизуемся как админ...")
await page.goto("http://localhost:3000/admin") await page.goto(f"{frontend_url}/admin")
await page.wait_for_load_state("networkidle") await page.wait_for_load_state("networkidle")
import os import os

View File

@@ -10,7 +10,7 @@ import os
from playwright.async_api import async_playwright from playwright.async_api import async_playwright
async def test_delete_button(): async def test_delete_button(frontend_url):
async with async_playwright() as p: async with async_playwright() as p:
# Определяем headless режим из переменной окружения # Определяем headless режим из переменной окружения
headless_mode = os.getenv("PLAYWRIGHT_HEADLESS", "false").lower() == "true" headless_mode = os.getenv("PLAYWRIGHT_HEADLESS", "false").lower() == "true"
@@ -20,8 +20,8 @@ async def test_delete_button():
page = await browser.new_page() page = await browser.new_page()
try: try:
print("🌐 Открываем админ-панель...") print(f"🌐 Открываем админ-панель на {frontend_url}...")
await page.goto("http://localhost:3000/login") await page.goto(f"{frontend_url}/login")
await page.wait_for_load_state("networkidle") await page.wait_for_load_state("networkidle")
print("🔐 Авторизуемся...") print("🔐 Авторизуемся...")
@@ -30,11 +30,11 @@ async def test_delete_button():
await page.click('button[type="submit"]') await page.click('button[type="submit"]')
# Ждем авторизации # Ждем авторизации
await page.wait_for_url("http://localhost:3000/admin/**", timeout=10000) await page.wait_for_url(f"{frontend_url}/admin/**", timeout=10000)
print("✅ Авторизация успешна") print("✅ Авторизация успешна")
print("📋 Переходим на страницу сообществ...") print("📋 Переходим на страницу сообществ...")
await page.goto("http://localhost:3000/admin/communities") await page.goto(f"{frontend_url}/admin/communities")
await page.wait_for_load_state("networkidle") await page.wait_for_load_state("networkidle")
print("🔍 Ищем таблицу сообществ...") print("🔍 Ищем таблицу сообществ...")

View File

@@ -10,7 +10,7 @@ import os
from playwright.async_api import async_playwright from playwright.async_api import async_playwright
async def test_login(): async def test_login(frontend_url):
async with async_playwright() as p: async with async_playwright() as p:
# Определяем headless режим из переменной окружения # Определяем headless режим из переменной окружения
headless_mode = os.getenv("PLAYWRIGHT_HEADLESS", "false").lower() == "true" headless_mode = os.getenv("PLAYWRIGHT_HEADLESS", "false").lower() == "true"
@@ -25,8 +25,8 @@ async def test_login():
page.on("console", lambda msg: print(f"📝 CONSOLE: {msg.text}")) page.on("console", lambda msg: print(f"📝 CONSOLE: {msg.text}"))
try: try:
print("🌐 Открываем страницу входа...") print(f"🌐 Открываем страницу входа на {frontend_url}...")
await page.goto("http://localhost:3000/login") await page.goto(f"{frontend_url}/login")
await page.wait_for_load_state("networkidle") await page.wait_for_load_state("networkidle")
print("📸 Делаем скриншот страницы входа...") print("📸 Делаем скриншот страницы входа...")