from pathlib import Path import random import re import sys import pytest from playwright.sync_api import expect PROJECT_ROOT = Path(__file__).resolve().parents[1] if str(PROJECT_ROOT) not in sys.path: sys.path.insert(0, str(PROJECT_ROOT)) from config.settings import settings from utils.logger import get_logger logger = get_logger(__name__) def test_header_download_app_navigation_then_home_return(page, ensure_guest_user): logger.info("使用 pytest-playwright 统一无头浏览器配置") logger.info("打开链接地址: %s", settings.base_url) page.goto(settings.base_url, wait_until="domcontentloaded") ensure_guest_user() logger.info("点击顶部 /app 导航链接") page.locator('header a[href="/app"]').first.click() logger.info("校验跳转到 /app 页面") expect(page).to_have_url(re.compile(r".*/app/?$"), timeout=settings.default_timeout) expect(page.locator("body")).to_be_visible(timeout=settings.default_timeout) logger.info("点击顶部首页链接返回首页") page.locator('header a[href="/"]').first.click() logger.info("校验返回首页成功") expect(page).to_have_url(re.compile(r".*/?$"), timeout=settings.default_timeout) expect(page.locator('button').first).to_be_visible(timeout=settings.default_timeout) def test_footer_navigation_to_partnerships_and_faq(page, ensure_guest_user): logger.info("使用 pytest-playwright 统一无头浏览器配置") logger.info("打开链接地址: %s", settings.base_url) page.goto(settings.base_url, wait_until="domcontentloaded") ensure_guest_user() logger.info("校验底部 Partnerships 和 FAQs 链接存在") expect(page.locator('footer a[href="/partnerships"]')).to_be_attached(timeout=settings.default_timeout) expect(page.locator('footer a[href="/faq"]')).to_be_attached(timeout=settings.default_timeout) logger.info("打开 Partnerships 页面") page.goto("/partnerships", wait_until="domcontentloaded") logger.info("校验跳转到 Partnerships 页面") expect(page).to_have_url(re.compile(r".*/partnerships/?$"), timeout=settings.default_timeout) expect(page.locator("body")).to_be_visible(timeout=settings.default_timeout) logger.info("打开 FAQ 页面") page.goto("/faq", wait_until="domcontentloaded") logger.info("校验跳转到 FAQ 页面") expect(page).to_have_url(re.compile(r".*/faq/?$"), timeout=settings.default_timeout) expect(page.locator("body")).to_be_visible(timeout=settings.default_timeout) def test_about_us_blog_random_category_article_browse_success(page, ensure_guest_user, attach_page_screenshot): logger.info("打开首页并进入 About Us 下的 Blog 页面") page.goto(settings.base_url, wait_until="domcontentloaded") ensure_guest_user() page.wait_for_timeout(2_000) about_us_menu = page.get_by_text("About Us", exact=True).first expect(about_us_menu).to_be_visible(timeout=settings.default_timeout) about_us_menu.click() blog_link = page.locator('a[href="/blog-detail"]', has_text="Blog").first expect(blog_link).to_be_visible(timeout=settings.default_timeout) blog_link.click() logger.info("校验 Blog 页面加载成功") expect(page).to_have_url(re.compile(r".*/blog-detail/?$"), timeout=settings.default_timeout) expect(page.locator("body")).to_contain_text("SEXUAL WELLNESS HUB", timeout=settings.default_timeout) category_buttons = page.locator("button").filter(has_not_text=re.compile(r"^\\d+$|Acce?pet", re.I)) expect(category_buttons.first).to_be_visible(timeout=settings.default_timeout) category_count = category_buttons.count() category_indexes = list(range(category_count)) random.shuffle(category_indexes) selected_category = None article_links = page.locator('a[href^="/blog-detail/"]') for category_index in category_indexes: category_button = category_buttons.nth(category_index) selected_category = category_button.inner_text(timeout=settings.default_timeout).strip() logger.info("随机选择 Blog 分类: %s", selected_category) category_button.click() page.wait_for_load_state("domcontentloaded") try: expect(article_links.first).to_be_visible(timeout=5_000) if article_links.count() > 0: break except AssertionError: logger.info("分类 %s 下暂无可浏览 Blog,继续随机尝试其他分类", selected_category) else: raise AssertionError("所有 Blog 分类下均未找到可浏览文章") article_count = article_links.count() article_index = random.randrange(article_count) article_link = article_links.nth(article_index) article_title = article_link.inner_text(timeout=settings.default_timeout).strip() logger.info("随机浏览 Blog 文章: %s", article_title) article_href = article_link.get_attribute("href") assert article_href is not None article_link.scroll_into_view_if_needed(timeout=settings.default_timeout) article_link.click() logger.info("校验 Blog 详情页加载成功并截图") expect(page).to_have_url(re.compile(r".*/blog-detail/.+"), timeout=settings.default_timeout) expect(page.locator("body")).to_be_visible(timeout=settings.default_timeout) if article_title: expect(page.locator("body")).to_contain_text(article_title, timeout=settings.default_timeout) attach_page_screenshot(f"Blog浏览成功_{selected_category}_{article_title or article_href}") def test_footer_social_media_links_open_then_return_home(page, ensure_guest_user): social_links = [ ("X", 'a[href="https://x.com/JoyhubOfficial"]', re.compile(r"https://(x|twitter)\.com/.*", re.I)), ( "Instagram", 'a[href="https://www.instagram.com/joyhub.official/#"]', re.compile(r"https://www\.instagram\.com/.*", re.I), ), ( "Reddit", 'a[href="https://www.reddit.com/r/JoyhubRemote/"]', re.compile(r"https://www\.reddit\.com/.*", re.I), ), ( "Discord", 'a[href="https://discord.com/invite/vZFQbTRZqe"]', re.compile(r"https://discord\.com/.*", re.I), ), ] logger.info("打开链接地址: %s", settings.base_url) page.goto(settings.base_url, wait_until="domcontentloaded") ensure_guest_user() for name, selector, expected_url in social_links: logger.info("滚动到首页底部,校验 %s 社交媒体链接 href", name) page.evaluate("window.scrollTo(0, document.body.scrollHeight)") link = page.locator(selector).first expect(link).to_be_attached(timeout=settings.default_timeout) link.scroll_into_view_if_needed(timeout=settings.default_timeout) social_href = link.get_attribute("href") assert social_href is not None assert expected_url.search(social_href), f"{name} 社交媒体链接不符合预期: {social_href}" if __name__ == "__main__": raise SystemExit(pytest.main([str(Path(__file__))]))