feat: 新增JoyHub UI自动化测试目录
1. 新增 Joyhub_ui_auto_test/ 目录: - tests/ - 测试用例目录 - pages/ - 页面元素定位 - config/ - 配置文件 - utils/ - 工具类 - test_data/ - 测试数据 - reports/ - 测试报告 - webapp-testing/ - WebApp测试相关 2. 配置文件: - pytest.ini - pytest配置 - requirements.txt - 依赖列表 - README.md - 项目说明
This commit is contained in:
155
Joyhub_ui_auto_test/tests/test_points_redemption_payment.py
Normal file
155
Joyhub_ui_auto_test/tests/test_points_redemption_payment.py
Normal file
@@ -0,0 +1,155 @@
|
||||
from pathlib import Path
|
||||
import random
|
||||
import re
|
||||
import sys
|
||||
|
||||
import pytest
|
||||
from playwright.sync_api import TimeoutError as PlaywrightTimeoutError
|
||||
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 tests.test_rewards_shopping_cart_login_logout import _accept_cookie_if_present
|
||||
from utils.logger import get_logger
|
||||
|
||||
logger = get_logger(__name__)
|
||||
|
||||
|
||||
REDEEM_NOW_SELECTORS = [
|
||||
'button:has-text("Redeem Now"):not([disabled])',
|
||||
'button:has-text("Redeem now"):not([disabled])',
|
||||
'button:has-text("立即兑换"):not([disabled])',
|
||||
]
|
||||
POINTS_PAY_SELECTORS = [
|
||||
'button:has-text("Pay"):not([disabled])',
|
||||
'button:has-text("Confirm"):not([disabled])',
|
||||
'button:has-text("Submit"):not([disabled])',
|
||||
'button:has-text("Place Order"):not([disabled])',
|
||||
'button:has-text("Redeem"):not([disabled])',
|
||||
'button:has-text("Confirm Redemption"):not([disabled])',
|
||||
'button:has-text("确认"):not([disabled])',
|
||||
'button:has-text("提交"):not([disabled])',
|
||||
'button:has-text("支付"):not([disabled])',
|
||||
]
|
||||
|
||||
|
||||
def _visible_locator(page, selectors, timeout=5_000):
|
||||
for selector in selectors:
|
||||
locator = page.locator(selector).first
|
||||
try:
|
||||
if locator.is_visible(timeout=timeout):
|
||||
return locator
|
||||
except PlaywrightTimeoutError:
|
||||
continue
|
||||
raise AssertionError(f"未找到可见元素: {selectors}")
|
||||
|
||||
|
||||
def _login_in_open_dialog(page):
|
||||
logger.info("在 Redeem Now 触发的登录弹窗中登录")
|
||||
login_inputs = page.locator('input[type="text"]')
|
||||
expect(login_inputs.first).to_be_visible(timeout=settings.default_timeout)
|
||||
login_inputs.nth(0).fill(settings.login_email)
|
||||
login_inputs.nth(1).fill(settings.verification_code)
|
||||
|
||||
confirmation_items = page.locator("div.inline-flex.cursor-pointer")
|
||||
expect(confirmation_items.nth(0)).to_be_visible(timeout=settings.default_timeout)
|
||||
expect(confirmation_items.nth(1)).to_be_visible(timeout=settings.default_timeout)
|
||||
confirmation_items.nth(0).click()
|
||||
confirmation_items.nth(1).click()
|
||||
|
||||
submit_button = page.locator("button").last
|
||||
expect(submit_button).to_be_enabled(timeout=settings.default_timeout)
|
||||
submit_button.click()
|
||||
|
||||
logger.info("等待登录弹窗关闭或兑换流程继续")
|
||||
expect(login_inputs.first).not_to_be_visible(timeout=settings.default_timeout)
|
||||
|
||||
|
||||
def _open_points_redemption_from_rewards(page):
|
||||
logger.info("未登录用户点击 Rewards 并进入 Points Redemption")
|
||||
rewards_link = page.locator('header a[href^="javascript:"]').filter(has_text="Rewards").first
|
||||
expect(rewards_link).to_be_attached(timeout=settings.default_timeout)
|
||||
rewards_link.click(force=True)
|
||||
|
||||
try:
|
||||
page.wait_for_function(
|
||||
"""
|
||||
() => Array.from(document.querySelectorAll('a[href="/points-redemption"]'))
|
||||
.some(element => !!(element.offsetWidth || element.offsetHeight || element.getClientRects().length))
|
||||
""",
|
||||
timeout=5_000,
|
||||
)
|
||||
page.locator('a[href="/points-redemption"]').filter(has_text="Points Redemption").first.click()
|
||||
except PlaywrightTimeoutError:
|
||||
logger.info("Rewards 下拉入口未稳定展示,直接进入 Points Redemption 页面")
|
||||
page.goto(settings.base_url.rstrip("/") + "/points-redemption", wait_until="domcontentloaded")
|
||||
|
||||
expect(page).to_have_url(re.compile(r".*/points-redemption/?"), timeout=settings.default_timeout)
|
||||
expect(page.locator("body")).to_be_visible(timeout=settings.default_timeout)
|
||||
|
||||
|
||||
def _open_random_redeemable_points_product(page):
|
||||
logger.info("随机选择一个积分商品并查找 Redeem Now")
|
||||
category_buttons = page.locator("section button").filter(has_not_text=re.compile(r"Accepet|Accept", re.I))
|
||||
expect(category_buttons.first).to_be_visible(timeout=settings.default_timeout)
|
||||
|
||||
category_indices = list(range(category_buttons.count()))
|
||||
random.shuffle(category_indices)
|
||||
last_error = None
|
||||
|
||||
for category_index in category_indices:
|
||||
try:
|
||||
logger.info("尝试积分商品分类/商品入口索引: %s", category_index)
|
||||
category_buttons.nth(category_index).click()
|
||||
page.wait_for_timeout(1_500)
|
||||
|
||||
if page.get_by_text(re.compile(r"currently do not support delivery", re.I)).first.is_visible(timeout=1_000):
|
||||
last_error = "当前国家/地区不支持积分商品配送"
|
||||
continue
|
||||
|
||||
redeem_button = _visible_locator(page, REDEEM_NOW_SELECTORS, timeout=5_000)
|
||||
expect(redeem_button).to_be_enabled(timeout=settings.default_timeout)
|
||||
redeem_button.click()
|
||||
return
|
||||
except (AssertionError, PlaywrightTimeoutError) as exc:
|
||||
last_error = exc
|
||||
logger.info("当前积分商品不可兑换,继续尝试下一个: %s", exc)
|
||||
|
||||
pytest.skip(f"当前测试环境未展示可兑换积分商品,无法执行 Redeem Now 主流程: {last_error}")
|
||||
|
||||
|
||||
def _complete_points_payment_after_login(page):
|
||||
logger.info("登录后继续完成积分商品支付/兑换")
|
||||
try:
|
||||
pay_button = _visible_locator(page, POINTS_PAY_SELECTORS, timeout=settings.default_timeout)
|
||||
expect(pay_button).to_be_enabled(timeout=settings.default_timeout)
|
||||
pay_button.click()
|
||||
except AssertionError:
|
||||
logger.info("登录后未出现独立确认按钮,检查是否已自动提交兑换")
|
||||
|
||||
result_text = page.get_by_text(
|
||||
re.compile(r"success|successful|completed|paid|payment|order|redeem|redemption|成功|订单|兑换", re.I)
|
||||
).first
|
||||
expect(result_text).to_be_visible(timeout=settings.default_timeout)
|
||||
|
||||
|
||||
def test_guest_points_product_redeem_now_login_then_points_payment_result(page, ensure_guest_user):
|
||||
logger.info("未登录用户从 Rewards 选择积分商品,Redeem Now 后登录并完成积分支付")
|
||||
page.goto(settings.base_url, wait_until="domcontentloaded")
|
||||
ensure_guest_user()
|
||||
|
||||
_open_points_redemption_from_rewards(page)
|
||||
_open_random_redeemable_points_product(page)
|
||||
|
||||
logger.info("校验 Redeem Now 后弹出登录弹窗")
|
||||
expect(page.locator('input[type="text"]').first).to_be_visible(timeout=settings.default_timeout)
|
||||
|
||||
_login_in_open_dialog(page)
|
||||
_complete_points_payment_after_login(page)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(pytest.main([str(Path(__file__))]))
|
||||
Reference in New Issue
Block a user