This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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"},
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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("🔍 Ищем таблицу сообществ...")
|
||||||
|
|||||||
@@ -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("📸 Делаем скриншот страницы входа...")
|
||||||
|
|||||||
Reference in New Issue
Block a user