Files
smart-management-auto-test/Joyhub_ui_auto_test/tests/test_points_redemption_payment.py
2026-05-13 18:07:36 +08:00

160 lines
6.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from pathlib import Path
import random
import re
import sys
import allure
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)
@allure.feature("积分兑换")
@allure.story("积分商品支付")
@allure.title("游客兑换积分商品后登录并完成积分支付")
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__))]))