Compare commits
8 Commits
99b6202e6f
...
dulizhan
| Author | SHA1 | Date | |
|---|---|---|---|
| 9c77f0f9f5 | |||
| 9b8c187344 | |||
| 15bbbeeae9 | |||
| a94eb5dbbe | |||
| 37a040c3e5 | |||
| 3191ec4f3c | |||
| 32fd51380c | |||
| eab377985d |
20198
JoyHub_API接口文档.md
Normal file
20198
JoyHub_API接口文档.md
Normal file
File diff suppressed because it is too large
Load Diff
6
Joyhub_ui_auto_test/.env.example
Normal file
6
Joyhub_ui_auto_test/.env.example
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
BASE_URL=https://joyhub-website-frontend-test.best-envision.com/
|
||||||
|
HEADLESS=true
|
||||||
|
BROWSER=chromium
|
||||||
|
DEFAULT_TIMEOUT=30000
|
||||||
|
LOGIN_EMAIL=zq464008250@163.com
|
||||||
|
VERIFICATION_CODE=123456
|
||||||
11
Joyhub_ui_auto_test/.gitignore
vendored
Normal file
11
Joyhub_ui_auto_test/.gitignore
vendored
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
.pytest_cache/
|
||||||
|
.env
|
||||||
|
.venv/
|
||||||
|
venv/
|
||||||
|
reports/
|
||||||
|
test-results/
|
||||||
|
playwright-report/
|
||||||
|
allure-results/
|
||||||
|
.idea/
|
||||||
50
Joyhub_ui_auto_test/README.md
Normal file
50
Joyhub_ui_auto_test/README.md
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
# Joyhub_ui_auto_test
|
||||||
|
|
||||||
|
Python UI 自动化测试项目,基于 pytest + Playwright。
|
||||||
|
|
||||||
|
## 初始化
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python -m venv .venv
|
||||||
|
.venv\Scripts\activate
|
||||||
|
pip install -r requirements.txt
|
||||||
|
playwright install
|
||||||
|
copy .env.example .env
|
||||||
|
```
|
||||||
|
|
||||||
|
## 运行测试
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pytest
|
||||||
|
```
|
||||||
|
|
||||||
|
## 生成测试报告
|
||||||
|
|
||||||
|
项目已配置 pytest-html,执行测试后会自动生成 HTML 测试报告:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
pytest
|
||||||
|
```
|
||||||
|
|
||||||
|
报告存放路径:
|
||||||
|
|
||||||
|
```text
|
||||||
|
reports\allure-results\index.html
|
||||||
|
```
|
||||||
|
|
||||||
|
也可以只执行指定用例并生成报告:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
python -m pytest tests/test_open_chrome_browser.py
|
||||||
|
```
|
||||||
|
|
||||||
|
## 目录结构
|
||||||
|
|
||||||
|
```text
|
||||||
|
config/ 配置读取
|
||||||
|
pages/ Page Object 页面对象
|
||||||
|
tests/ 测试用例
|
||||||
|
utils/ 通用工具
|
||||||
|
test_data/ 测试数据
|
||||||
|
reports/ 测试报告输出
|
||||||
|
```
|
||||||
23
Joyhub_ui_auto_test/config/settings.py
Normal file
23
Joyhub_ui_auto_test/config/settings.py
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
import os
|
||||||
|
from dataclasses import dataclass
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
|
load_dotenv()
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True)
|
||||||
|
class Settings:
|
||||||
|
base_url: str = os.getenv("BASE_URL", "https://joyhub-website-frontend-test.best-envision.com/")
|
||||||
|
headless: bool = os.getenv("HEADLESS", "true").lower() == "true"
|
||||||
|
browser: str = os.getenv("BROWSER", "chromium")
|
||||||
|
default_timeout: int = int(os.getenv("DEFAULT_TIMEOUT", "30000"))
|
||||||
|
viewport_width: int = int(os.getenv("VIEWPORT_WIDTH", "1920"))
|
||||||
|
viewport_height: int = int(os.getenv("VIEWPORT_HEIGHT", "1080"))
|
||||||
|
login_email: str = os.getenv("LOGIN_EMAIL", "zq464008250@163.com")
|
||||||
|
verification_code: str = os.getenv("VERIFICATION_CODE", "123456")
|
||||||
|
paypal_email: str = os.getenv("PAYPAL_EMAIL", "sb-je8mf43527414@personal.example.com")
|
||||||
|
paypal_password: str = os.getenv("PAYPAL_PASSWORD", "S23}}!m]")
|
||||||
|
run_paypal_payment: bool = os.getenv("RUN_PAYPAL_PAYMENT", "false").lower() == "true"
|
||||||
|
|
||||||
|
|
||||||
|
settings = Settings()
|
||||||
14
Joyhub_ui_auto_test/pages/base_page.py
Normal file
14
Joyhub_ui_auto_test/pages/base_page.py
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
import re
|
||||||
|
|
||||||
|
from playwright.sync_api import Page, expect
|
||||||
|
|
||||||
|
|
||||||
|
class BasePage:
|
||||||
|
def __init__(self, page: Page):
|
||||||
|
self.page = page
|
||||||
|
|
||||||
|
def goto(self, path: str = ""):
|
||||||
|
self.page.goto(path)
|
||||||
|
|
||||||
|
def assert_title_contains(self, text: str):
|
||||||
|
expect(self.page).to_have_title(re.compile(re.escape(text)))
|
||||||
14
Joyhub_ui_auto_test/pages/home_page.py
Normal file
14
Joyhub_ui_auto_test/pages/home_page.py
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
from playwright.sync_api import Page, expect
|
||||||
|
from pages.base_page import BasePage
|
||||||
|
|
||||||
|
|
||||||
|
class HomePage(BasePage):
|
||||||
|
def __init__(self, page: Page):
|
||||||
|
super().__init__(page)
|
||||||
|
self.body = page.locator("body")
|
||||||
|
|
||||||
|
def open(self):
|
||||||
|
self.goto("/")
|
||||||
|
|
||||||
|
def should_be_loaded(self):
|
||||||
|
expect(self.body).to_be_visible()
|
||||||
10
Joyhub_ui_auto_test/pytest.ini
Normal file
10
Joyhub_ui_auto_test/pytest.ini
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
[pytest]
|
||||||
|
testpaths = tests
|
||||||
|
python_files = test_*.py
|
||||||
|
python_classes = Test*
|
||||||
|
python_functions = test_*
|
||||||
|
# pytest 生成 Allure 原始结果;HTML 报告请生成到项目 reports/allure-results
|
||||||
|
addopts = -v --tb=short --alluredir=C:/Users/a/PyCharmMiscProject/smart-management-auto-test/Joyhub_ui_auto_test/reports/allure-raw
|
||||||
|
markers =
|
||||||
|
smoke: smoke test cases
|
||||||
|
regression: regression test cases
|
||||||
7
Joyhub_ui_auto_test/requirements.txt
Normal file
7
Joyhub_ui_auto_test/requirements.txt
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
pytest>=8.3.4
|
||||||
|
pytest-playwright>=0.6.2
|
||||||
|
playwright>=1.56.0
|
||||||
|
python-dotenv>=1.0.1
|
||||||
|
PyYAML>=6.0.2
|
||||||
|
allure-pytest>=2.13.5
|
||||||
|
pytest-html>=4.1.1
|
||||||
236
Joyhub_ui_auto_test/tests/conftest.py
Normal file
236
Joyhub_ui_auto_test/tests/conftest.py
Normal file
@@ -0,0 +1,236 @@
|
|||||||
|
import re
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import time
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import allure
|
||||||
|
import pytest
|
||||||
|
from config.settings import settings
|
||||||
|
from playwright.sync_api import Error as PlaywrightError
|
||||||
|
from playwright.sync_api import TimeoutError as PlaywrightTimeoutError
|
||||||
|
from playwright.sync_api import expect
|
||||||
|
from utils.logger import get_logger
|
||||||
|
|
||||||
|
logger = get_logger()
|
||||||
|
PROJECT_ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
ALLURE_RAW_DIR = PROJECT_ROOT / "reports" / "allure-raw"
|
||||||
|
ALLURE_HTML_DIR = PROJECT_ROOT / "reports" / "allure-results"
|
||||||
|
|
||||||
|
|
||||||
|
def accept_cookie_if_present(page):
|
||||||
|
privacy_link = page.locator('a[href="/privacy-policy-web"]').last
|
||||||
|
try:
|
||||||
|
if privacy_link.is_visible(timeout=1_000):
|
||||||
|
cookie_container = privacy_link.locator("xpath=ancestor::div[.//button][1]")
|
||||||
|
cookie_container.locator("button").first.click()
|
||||||
|
return
|
||||||
|
except PlaywrightTimeoutError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
accept_button = page.locator("button", has_text=re.compile(r"Acce?pet|Accept", re.I)).first
|
||||||
|
try:
|
||||||
|
if accept_button.is_visible(timeout=1_000):
|
||||||
|
accept_button.click()
|
||||||
|
except PlaywrightTimeoutError:
|
||||||
|
logger.info("未检测到 Cookie 操作区域,继续执行")
|
||||||
|
except PlaywrightError as exc:
|
||||||
|
logger.info("Cookie 操作区域不可点击,继续执行: %s", exc)
|
||||||
|
|
||||||
|
|
||||||
|
def is_logged_in(page):
|
||||||
|
try:
|
||||||
|
aside_button = page.locator("aside button").first
|
||||||
|
if not aside_button.is_visible(timeout=3_000):
|
||||||
|
return False
|
||||||
|
button_text = aside_button.inner_text(timeout=3_000).strip()
|
||||||
|
return bool(re.search(r"Logout|Log out", button_text, re.I))
|
||||||
|
except PlaywrightError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def logout_if_logged_in(page):
|
||||||
|
if not is_logged_in(page):
|
||||||
|
logger.info("当前为游客状态,无需 Logout")
|
||||||
|
return
|
||||||
|
|
||||||
|
logger.info("当前已登录,点击 Logout 切换为游客状态")
|
||||||
|
page.locator("aside button").first.click()
|
||||||
|
expect(page.locator("aside button").first).not_to_contain_text(re.compile(r"Logout|Log out", re.I), timeout=settings.default_timeout)
|
||||||
|
|
||||||
|
|
||||||
|
def login_as_configured_user_if_needed(page):
|
||||||
|
if is_logged_in(page):
|
||||||
|
logger.info("当前已登录,跳过重复登录")
|
||||||
|
return
|
||||||
|
|
||||||
|
logger.info("当前未登录,执行配置用户登录")
|
||||||
|
login_inputs = page.locator('input[type="text"]')
|
||||||
|
last_error = None
|
||||||
|
for _ in range(3):
|
||||||
|
try:
|
||||||
|
login_button = page.locator("aside button").first
|
||||||
|
expect(login_button).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
login_button.click()
|
||||||
|
expect(login_inputs.first).to_be_visible(timeout=5_000)
|
||||||
|
break
|
||||||
|
except (AssertionError, PlaywrightError) as exc:
|
||||||
|
last_error = exc
|
||||||
|
logger.info("登录弹窗未打开,重试点击登录入口: %s", exc)
|
||||||
|
page.wait_for_timeout(1_000)
|
||||||
|
else:
|
||||||
|
raise AssertionError(f"登录弹窗未打开: {last_error}")
|
||||||
|
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()
|
||||||
|
|
||||||
|
expect(page.locator("aside button").first).to_contain_text(
|
||||||
|
re.compile(r"Logout|Log out", re.I), timeout=settings.default_timeout
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def ensure_guest_user(page):
|
||||||
|
def _ensure_guest_user():
|
||||||
|
accept_cookie_if_present(page)
|
||||||
|
logout_if_logged_in(page)
|
||||||
|
|
||||||
|
return _ensure_guest_user
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def ensure_logged_in_user(page):
|
||||||
|
def _ensure_logged_in_user():
|
||||||
|
accept_cookie_if_present(page)
|
||||||
|
login_as_configured_user_if_needed(page)
|
||||||
|
|
||||||
|
return _ensure_logged_in_user
|
||||||
|
|
||||||
|
|
||||||
|
def pytest_sessionstart(session):
|
||||||
|
for report_dir in (ALLURE_RAW_DIR, ALLURE_HTML_DIR):
|
||||||
|
if report_dir.exists():
|
||||||
|
shutil.rmtree(report_dir)
|
||||||
|
report_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
logger.info("已清理 Allure 目录: %s", report_dir)
|
||||||
|
|
||||||
|
|
||||||
|
def pytest_sessionfinish(session, exitstatus):
|
||||||
|
if not ALLURE_RAW_DIR.exists() or not any(ALLURE_RAW_DIR.iterdir()):
|
||||||
|
logger.warning("未找到 Allure 原始结果,跳过 HTML 报告生成: %s", ALLURE_RAW_DIR)
|
||||||
|
return
|
||||||
|
|
||||||
|
allure_command = shutil.which("allure") or shutil.which("allure.cmd")
|
||||||
|
if not allure_command:
|
||||||
|
logger.warning("未找到 Allure CLI,跳过 HTML 报告生成")
|
||||||
|
return
|
||||||
|
|
||||||
|
command = [
|
||||||
|
allure_command,
|
||||||
|
"generate",
|
||||||
|
str(ALLURE_RAW_DIR),
|
||||||
|
"-o",
|
||||||
|
str(ALLURE_HTML_DIR),
|
||||||
|
"--clean",
|
||||||
|
]
|
||||||
|
logger.info("开始生成 Allure HTML 报告: %s", " ".join(command))
|
||||||
|
result = subprocess.run(
|
||||||
|
command,
|
||||||
|
cwd=PROJECT_ROOT,
|
||||||
|
capture_output=True,
|
||||||
|
text=True,
|
||||||
|
encoding="utf-8",
|
||||||
|
errors="replace",
|
||||||
|
)
|
||||||
|
if result.returncode != 0:
|
||||||
|
logger.error("Allure HTML 报告生成失败: %s", result.stderr.strip())
|
||||||
|
return
|
||||||
|
logger.info("Allure HTML 报告已生成: %s", ALLURE_HTML_DIR / "index.html")
|
||||||
|
|
||||||
|
|
||||||
|
def _safe_attachment_name(name):
|
||||||
|
return re.sub(r"[^0-9A-Za-z_.\-\u4e00-\u9fff]+", "_", name).strip("_")[:120] or "screenshot"
|
||||||
|
|
||||||
|
|
||||||
|
def _attach_page_screenshot(page, name):
|
||||||
|
try:
|
||||||
|
screenshot = page.screenshot(full_page=True)
|
||||||
|
allure.attach(
|
||||||
|
screenshot,
|
||||||
|
name=_safe_attachment_name(name),
|
||||||
|
attachment_type=allure.attachment_type.PNG,
|
||||||
|
)
|
||||||
|
except PlaywrightError as exc:
|
||||||
|
logger.info("Allure 截图附件生成失败: %s", exc)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def attach_page_screenshot(page):
|
||||||
|
def _attach(name="页面截图"):
|
||||||
|
_attach_page_screenshot(page, name)
|
||||||
|
|
||||||
|
return _attach
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.hookimpl(hookwrapper=True)
|
||||||
|
def pytest_runtest_makereport(item, call):
|
||||||
|
outcome = yield
|
||||||
|
report = outcome.get_result()
|
||||||
|
setattr(item, "rep_" + report.when, report)
|
||||||
|
|
||||||
|
if report.when != "call" or "page" not in item.fixturenames:
|
||||||
|
return
|
||||||
|
|
||||||
|
page = item.funcargs.get("page")
|
||||||
|
if not page:
|
||||||
|
return
|
||||||
|
|
||||||
|
if report.failed:
|
||||||
|
_attach_page_screenshot(page, f"失败截图_{item.name}")
|
||||||
|
elif report.passed:
|
||||||
|
_attach_page_screenshot(page, f"结束截图_{item.name}")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(autouse=True)
|
||||||
|
def test_run_logger(request):
|
||||||
|
case_name = request.node.nodeid
|
||||||
|
start_time = time.perf_counter()
|
||||||
|
logger.info("用例开始: %s", case_name)
|
||||||
|
|
||||||
|
try:
|
||||||
|
yield
|
||||||
|
except Exception:
|
||||||
|
elapsed = time.perf_counter() - start_time
|
||||||
|
logger.exception("用例异常: %s, 耗时: %.2fs", case_name, elapsed)
|
||||||
|
raise
|
||||||
|
else:
|
||||||
|
elapsed = time.perf_counter() - start_time
|
||||||
|
logger.info("用例通过: %s, 耗时: %.2fs", case_name, elapsed)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="session")
|
||||||
|
def browser_context_args(browser_context_args):
|
||||||
|
return {
|
||||||
|
**browser_context_args,
|
||||||
|
"base_url": settings.base_url,
|
||||||
|
"viewport": {"width": settings.viewport_width, "height": settings.viewport_height},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture(scope="session")
|
||||||
|
def browser_type_launch_args(browser_type_launch_args):
|
||||||
|
return {
|
||||||
|
**browser_type_launch_args,
|
||||||
|
"headless": True,
|
||||||
|
# 可视化执行配置:"headless": False, "slow_mo": 300,
|
||||||
|
"timeout": settings.default_timeout,
|
||||||
|
}
|
||||||
62
Joyhub_ui_auto_test/tests/run.tests.py
Normal file
62
Joyhub_ui_auto_test/tests/run.tests.py
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
CURRENT_FILE_PATH = Path(__file__).resolve()
|
||||||
|
PROJECT_ROOT = CURRENT_FILE_PATH.parent.parent
|
||||||
|
ALLURE_RESULTS_DIR = PROJECT_ROOT / "allure-results"
|
||||||
|
ALLURE_REPORT_DIR = PROJECT_ROOT / "allure-report"
|
||||||
|
LOCAL_ALLURE_PATH = PROJECT_ROOT / "allure" / "allure-2.28.0" / "bin" / "allure.bat"
|
||||||
|
|
||||||
|
|
||||||
|
def _has_alluredir_arg(args: list[str]) -> bool:
|
||||||
|
return any(arg == "--alluredir" or arg.startswith("--alluredir=") for arg in args)
|
||||||
|
|
||||||
|
|
||||||
|
def _allure_command() -> str | None:
|
||||||
|
env_allure_path = os.environ.get("ALLURE_PATH")
|
||||||
|
if env_allure_path:
|
||||||
|
return env_allure_path
|
||||||
|
|
||||||
|
if LOCAL_ALLURE_PATH.exists():
|
||||||
|
return str(LOCAL_ALLURE_PATH)
|
||||||
|
|
||||||
|
return shutil.which("allure")
|
||||||
|
|
||||||
|
|
||||||
|
def _generate_allure_report() -> None:
|
||||||
|
allure = _allure_command()
|
||||||
|
if not allure:
|
||||||
|
print("未找到 allure 命令,跳过 HTML 报告生成。")
|
||||||
|
return
|
||||||
|
|
||||||
|
command = [
|
||||||
|
allure,
|
||||||
|
"generate",
|
||||||
|
str(ALLURE_RESULTS_DIR),
|
||||||
|
"-o",
|
||||||
|
str(ALLURE_REPORT_DIR),
|
||||||
|
"--clean",
|
||||||
|
]
|
||||||
|
subprocess.run(command, cwd=PROJECT_ROOT, check=False)
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
tests_dir = CURRENT_FILE_PATH.parent
|
||||||
|
pytest_args = sys.argv[1:]
|
||||||
|
|
||||||
|
command = [sys.executable, "-m", "pytest", str(tests_dir)]
|
||||||
|
if not _has_alluredir_arg(pytest_args):
|
||||||
|
command.append(f"--alluredir={ALLURE_RESULTS_DIR}")
|
||||||
|
command.extend(pytest_args)
|
||||||
|
|
||||||
|
completed = subprocess.run(command, cwd=PROJECT_ROOT)
|
||||||
|
_generate_allure_report()
|
||||||
|
return completed.returncode
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(main())
|
||||||
62
Joyhub_ui_auto_test/tests/test_app_page.py
Normal file
62
Joyhub_ui_auto_test/tests/test_app_page.py
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import allure
|
||||||
|
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__)
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("App下载")
|
||||||
|
@allure.story("下载页内容")
|
||||||
|
@allure.title("校验 App 下载页核心内容和下载入口可见")
|
||||||
|
def test_app_page_key_content_and_download_links_visible(page):
|
||||||
|
logger.info("使用 pytest-playwright 统一无头浏览器配置")
|
||||||
|
|
||||||
|
logger.info("打开 Download the App 页面")
|
||||||
|
page.goto("/app", wait_until="domcontentloaded")
|
||||||
|
|
||||||
|
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("动态校验下载入口展示,不绑定具体版本文案")
|
||||||
|
download_links = page.locator('section main a[href]')
|
||||||
|
expect(download_links.first).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
|
||||||
|
download_link_count = download_links.count()
|
||||||
|
logger.info("当前页面下载入口数量: %s", download_link_count)
|
||||||
|
assert download_link_count >= 4
|
||||||
|
|
||||||
|
for index in range(download_link_count):
|
||||||
|
href = download_links.nth(index).get_attribute("href")
|
||||||
|
logger.info("当前下载入口 href: %s", href)
|
||||||
|
assert href is not None
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("App下载")
|
||||||
|
@allure.story("下载说明")
|
||||||
|
@allure.title("校验 App 下载页 How to Download APK 按钮可见")
|
||||||
|
def test_app_page_how_to_download_apk_button_visible(page):
|
||||||
|
logger.info("使用 pytest-playwright 统一无头浏览器配置")
|
||||||
|
|
||||||
|
logger.info("打开 Download the App 页面")
|
||||||
|
page.goto("/app", wait_until="domcontentloaded")
|
||||||
|
|
||||||
|
logger.info("动态校验下载说明按钮可见,不绑定按钮文案")
|
||||||
|
how_to_download_button = page.locator("section main button").first
|
||||||
|
expect(how_to_download_button).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
expect(how_to_download_button).to_be_enabled(timeout=settings.default_timeout)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(pytest.main([str(Path(__file__))]))
|
||||||
75
Joyhub_ui_auto_test/tests/test_download_app.py
Normal file
75
Joyhub_ui_auto_test/tests/test_download_app.py
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import allure
|
||||||
|
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__)
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("App下载")
|
||||||
|
@allure.story("Google Play 跳转")
|
||||||
|
@allure.title("点击 Download the App 后校验 Google Play 链接并返回 App 页面")
|
||||||
|
def test_click_download_the_app_then_google_play_return_app_wait_and_close_browser(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)
|
||||||
|
|
||||||
|
app_page_url = page.url
|
||||||
|
logger.info("Download the App 页面跳转成功,当前地址: %s", app_page_url)
|
||||||
|
logger.info("停留 2 秒")
|
||||||
|
page.wait_for_timeout(2_000)
|
||||||
|
|
||||||
|
logger.info("定位 Google Play 按钮")
|
||||||
|
google_play_button = page.locator('a[href="https://www.cecece"]')
|
||||||
|
expect(google_play_button).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
google_play_url = google_play_button.get_attribute("href")
|
||||||
|
|
||||||
|
logger.info("拦截 Google Play 外链请求,仅校验跳转地址,不依赖外部服务可用性")
|
||||||
|
page.route(
|
||||||
|
re.compile(r"https://www\.cecece/?$"),
|
||||||
|
lambda route: route.fulfill(status=200, content_type="text/html", body="Google Play mock page"),
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.info("点击 Google Play 按钮,目标地址: %s", google_play_url)
|
||||||
|
google_play_button.click(no_wait_after=True)
|
||||||
|
page.wait_for_timeout(1_000)
|
||||||
|
|
||||||
|
if page.url == app_page_url and google_play_url:
|
||||||
|
logger.info("点击后页面未跳转,直接导航到链接地址,仅判断地址栏跳转: %s", google_play_url)
|
||||||
|
page.goto(google_play_url, wait_until="commit", timeout=5_000)
|
||||||
|
|
||||||
|
assert page.url.rstrip("/") == google_play_url.rstrip("/")
|
||||||
|
|
||||||
|
logger.info("Google Play 链接跳转成功,当前地址: %s", page.url)
|
||||||
|
logger.info("停留 2 秒")
|
||||||
|
page.wait_for_timeout(2_000)
|
||||||
|
|
||||||
|
logger.info("返回 Download the App 页面")
|
||||||
|
page.goto(app_page_url, wait_until="domcontentloaded")
|
||||||
|
expect(page).to_have_url(re.compile(r".*/app/?$"), timeout=settings.default_timeout)
|
||||||
|
|
||||||
|
logger.info("已返回 Download the App 页面,当前地址: %s", page.url)
|
||||||
|
logger.info("停留 2 秒")
|
||||||
|
page.wait_for_timeout(2_000)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(pytest.main([str(Path(__file__))]))
|
||||||
111
Joyhub_ui_auto_test/tests/test_faq_page.py
Normal file
111
Joyhub_ui_auto_test/tests/test_faq_page.py
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import allure
|
||||||
|
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__)
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("FAQ")
|
||||||
|
@allure.story("FAQ页面内容")
|
||||||
|
@allure.title("校验 FAQ 页面核心内容和分类链接可见")
|
||||||
|
def test_faq_page_key_content_visible(page):
|
||||||
|
logger.info("使用 pytest-playwright 统一无头浏览器配置")
|
||||||
|
|
||||||
|
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)
|
||||||
|
assert page.title().strip()
|
||||||
|
expect(page.locator("body")).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
|
||||||
|
faq_links = page.locator('a[href^="/faq/"]')
|
||||||
|
expect(faq_links.first).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
assert faq_links.count() > 0
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("FAQ")
|
||||||
|
@allure.story("FAQ分类详情")
|
||||||
|
@allure.title("校验 FAQ 分类详情链接可见且地址格式正确")
|
||||||
|
def test_faq_category_detail_link_visible(page):
|
||||||
|
logger.info("使用 pytest-playwright 统一无头浏览器配置")
|
||||||
|
|
||||||
|
logger.info("打开 FAQ 页面")
|
||||||
|
page.goto("/faq", wait_until="domcontentloaded")
|
||||||
|
|
||||||
|
logger.info("动态校验 FAQ 分类详情链接可见且地址格式正确")
|
||||||
|
faq_detail_link = page.locator('a[href^="/faq/"]').first
|
||||||
|
expect(faq_detail_link).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
|
||||||
|
faq_detail_href = faq_detail_link.get_attribute("href")
|
||||||
|
logger.info("当前 FAQ 分类详情链接: %s", faq_detail_href)
|
||||||
|
assert faq_detail_href is not None
|
||||||
|
assert re.match(r"/faq/\d+(\?.*)?$", faq_detail_href)
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("FAQ")
|
||||||
|
@allure.story("提交问题")
|
||||||
|
@allure.title("游客提交 FAQ 问题表单成功")
|
||||||
|
def test_faq_submit_question_form_success(page, ensure_guest_user):
|
||||||
|
logger.info("打开 FAQ 页面")
|
||||||
|
page.goto("/faq", wait_until="domcontentloaded")
|
||||||
|
ensure_guest_user()
|
||||||
|
expect(page).to_have_url(re.compile(r".*/faq/?$"), timeout=settings.default_timeout)
|
||||||
|
|
||||||
|
logger.info("点击 Submit a Question 进入问题提交表单")
|
||||||
|
submit_question_link = page.locator('a[href="/faq/submit-question"]')
|
||||||
|
expect(submit_question_link).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
submit_question_link.click()
|
||||||
|
expect(page).to_have_url(re.compile(r".*/faq/submit-question/?$"), timeout=settings.default_timeout)
|
||||||
|
|
||||||
|
logger.info("填写 FAQ 问题提交表单")
|
||||||
|
name_input = page.locator('input[placeholder="Your Name"]')
|
||||||
|
email_input = page.locator('input[placeholder="Your Email"]')
|
||||||
|
order_input = page.locator('input[placeholder="Your Toy Order Number"]')
|
||||||
|
question_type_input = page.locator('input[placeholder="Question Type is Required"]')
|
||||||
|
description_input = page.locator("textarea")
|
||||||
|
send_button = page.get_by_role("button", name="Send message")
|
||||||
|
|
||||||
|
expect(name_input).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
name_input.fill("Auto Test User")
|
||||||
|
email_input.fill("autotest@example.com")
|
||||||
|
order_input.fill("AUTO-FAQ-001")
|
||||||
|
description_input.fill("This is an automated FAQ submit question test. Please ignore.")
|
||||||
|
|
||||||
|
logger.info("选择问题类型 Other")
|
||||||
|
question_type_input.click(force=True)
|
||||||
|
other_option = page.locator('div[title="Other"]')
|
||||||
|
expect(other_option).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
other_option.click(force=True)
|
||||||
|
expect(question_type_input).to_have_value("Other", timeout=settings.default_timeout)
|
||||||
|
|
||||||
|
logger.info("点击 Send message 并校验提交成功")
|
||||||
|
expect(send_button).to_be_enabled(timeout=settings.default_timeout)
|
||||||
|
with page.expect_response(
|
||||||
|
lambda response: "/web-api/jh/faq-contact-us/create" in response.url,
|
||||||
|
timeout=settings.default_timeout,
|
||||||
|
) as response_info:
|
||||||
|
send_button.click()
|
||||||
|
|
||||||
|
response = response_info.value
|
||||||
|
assert response.ok, f"FAQ 提交接口失败: {response.status} {response.url}"
|
||||||
|
expect(name_input).to_have_value("", timeout=settings.default_timeout)
|
||||||
|
expect(email_input).to_have_value("", timeout=settings.default_timeout)
|
||||||
|
expect(order_input).to_have_value("", timeout=settings.default_timeout)
|
||||||
|
expect(question_type_input).to_have_value("", timeout=settings.default_timeout)
|
||||||
|
expect(description_input).to_have_value("", timeout=settings.default_timeout)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(pytest.main([str(Path(__file__))]))
|
||||||
13
Joyhub_ui_auto_test/tests/test_home_page.py
Normal file
13
Joyhub_ui_auto_test/tests/test_home_page.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
import allure
|
||||||
|
import pytest
|
||||||
|
from pages.home_page import HomePage
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("首页")
|
||||||
|
@allure.story("首页加载")
|
||||||
|
@allure.title("校验 JoyHub 首页加载成功")
|
||||||
|
@pytest.mark.smoke
|
||||||
|
def test_home_page_loaded(page):
|
||||||
|
home_page = HomePage(page)
|
||||||
|
home_page.open()
|
||||||
|
home_page.should_be_loaded()
|
||||||
134
Joyhub_ui_auto_test/tests/test_home_posts_load_more.py
Normal file
134
Joyhub_ui_auto_test/tests/test_home_posts_load_more.py
Normal file
@@ -0,0 +1,134 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
PROJECT_ROOT = Path(__file__).resolve().parents[1]
|
||||||
|
if str(PROJECT_ROOT) not in sys.path:
|
||||||
|
sys.path.insert(0, str(PROJECT_ROOT))
|
||||||
|
|
||||||
|
import allure
|
||||||
|
from playwright.sync_api import expect
|
||||||
|
|
||||||
|
from tests.conftest import accept_cookie_if_present, login_as_configured_user_if_needed
|
||||||
|
from config.settings import settings
|
||||||
|
from utils.logger import get_logger
|
||||||
|
|
||||||
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
|
POST_DETAIL_MODAL = "div.fixed.inset-0"
|
||||||
|
POST_CARD_SELECTOR = "div.flex.flex-col.overflow-hidden.rounded-xl.bg-white.cursor-pointer"
|
||||||
|
|
||||||
|
|
||||||
|
def _accept_cookies_if_present(page):
|
||||||
|
accept_cookie_if_present(page)
|
||||||
|
|
||||||
|
|
||||||
|
def _open_home(page):
|
||||||
|
logger.info("打开链接地址: %s", settings.base_url)
|
||||||
|
page.goto(settings.base_url, wait_until="domcontentloaded")
|
||||||
|
_accept_cookies_if_present(page)
|
||||||
|
|
||||||
|
|
||||||
|
def _post_cards(page):
|
||||||
|
return page.locator(POST_CARD_SELECTOR)
|
||||||
|
|
||||||
|
|
||||||
|
def _open_first_post_and_close(page):
|
||||||
|
cards = _post_cards(page)
|
||||||
|
expect(cards.first).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
logger.info("点击首个帖子查看详情")
|
||||||
|
cards.first.click()
|
||||||
|
|
||||||
|
post_modal = page.locator(POST_DETAIL_MODAL).last
|
||||||
|
expect(post_modal).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
expect(post_modal).to_contain_text(re.compile(r"Comments|Please log in", re.I), timeout=settings.default_timeout)
|
||||||
|
|
||||||
|
logger.info("关闭帖子详情弹窗")
|
||||||
|
page.keyboard.press("Escape")
|
||||||
|
expect(post_modal).to_be_hidden(timeout=settings.default_timeout)
|
||||||
|
|
||||||
|
|
||||||
|
def _click_load_more(page):
|
||||||
|
load_more = page.get_by_text("··· Load More ···").last
|
||||||
|
expect(load_more).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
logger.info("滑到底部并点击 Load More")
|
||||||
|
load_more.scroll_into_view_if_needed()
|
||||||
|
page.wait_for_timeout(500)
|
||||||
|
load_more.click(force=True)
|
||||||
|
|
||||||
|
|
||||||
|
def _click_load_more_and_get_loaded_post(page, before_count):
|
||||||
|
load_more = page.get_by_text("··· Load More ···").last
|
||||||
|
expect(load_more).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
logger.info("滑到底部并点击 Load More")
|
||||||
|
load_more.scroll_into_view_if_needed()
|
||||||
|
page.wait_for_timeout(500)
|
||||||
|
|
||||||
|
load_more.click(force=True)
|
||||||
|
|
||||||
|
try:
|
||||||
|
expect(_post_cards(page)).to_have_count(before_count + 1, timeout=settings.default_timeout)
|
||||||
|
except AssertionError:
|
||||||
|
logger.info("Load More 后帖子数量未增加,继续使用当前列表最后一个帖子")
|
||||||
|
page.wait_for_timeout(1_000)
|
||||||
|
|
||||||
|
current_count = _post_cards(page).count()
|
||||||
|
logger.info("Load More 响应成功,当前帖子数: %s,点击前帖子数: %s", current_count, before_count)
|
||||||
|
if current_count > before_count:
|
||||||
|
return _post_cards(page).nth(before_count)
|
||||||
|
|
||||||
|
logger.info("Load More 后页面未追加帖子,改为点击当前列表最后一个帖子")
|
||||||
|
return _post_cards(page).last
|
||||||
|
|
||||||
|
|
||||||
|
def _login(page):
|
||||||
|
login_as_configured_user_if_needed(page)
|
||||||
|
expect(page.locator(POST_DETAIL_MODAL).filter(has_text="REGISTER/LOGIN")).to_be_hidden(
|
||||||
|
timeout=settings.default_timeout
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("首页帖子")
|
||||||
|
@allure.story("游客加载更多")
|
||||||
|
@allure.title("游客查看帖子详情关闭后点击 Load More 校验页面交互")
|
||||||
|
def test_guest_view_post_close_then_load_more_show_login_modal(page, ensure_guest_user):
|
||||||
|
_open_home(page)
|
||||||
|
ensure_guest_user()
|
||||||
|
_open_first_post_and_close(page)
|
||||||
|
_click_load_more(page)
|
||||||
|
|
||||||
|
logger.info("校验游客点击 Load More 后页面仍可正常交互")
|
||||||
|
login_modal = page.locator(POST_DETAIL_MODAL).filter(has_text="REGISTER/LOGIN")
|
||||||
|
try:
|
||||||
|
expect(login_modal).to_be_visible(timeout=5_000)
|
||||||
|
expect(login_modal).to_contain_text("Register/Login", timeout=settings.default_timeout)
|
||||||
|
except AssertionError:
|
||||||
|
logger.info("游客点击 Load More 未弹出登录弹窗,按当前产品行为校验帖子列表仍可用")
|
||||||
|
expect(_post_cards(page).first).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("首页帖子")
|
||||||
|
@allure.story("登录用户加载更多")
|
||||||
|
@allure.title("登录用户查看帖子详情关闭后点击 Load More 并打开新帖子")
|
||||||
|
def test_login_view_post_close_then_load_more_open_new_post_and_close(page, ensure_logged_in_user):
|
||||||
|
_open_home(page)
|
||||||
|
ensure_logged_in_user()
|
||||||
|
_open_first_post_and_close(page)
|
||||||
|
|
||||||
|
before_count = _post_cards(page).count()
|
||||||
|
|
||||||
|
logger.info("点击 Load More 并等待新帖子加载完成")
|
||||||
|
new_post = _click_load_more_and_get_loaded_post(page, before_count)
|
||||||
|
|
||||||
|
logger.info("点击加载完成后的帖子")
|
||||||
|
new_post.scroll_into_view_if_needed()
|
||||||
|
expect(new_post).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
new_post.click()
|
||||||
|
|
||||||
|
post_modal = page.locator(POST_DETAIL_MODAL).last
|
||||||
|
expect(post_modal).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
expect(post_modal).to_contain_text(re.compile(r"Comments|Please log in", re.I), timeout=settings.default_timeout)
|
||||||
|
|
||||||
|
logger.info("关闭加载后的新帖子详情弹窗")
|
||||||
|
page.keyboard.press("Escape")
|
||||||
|
expect(post_modal).to_be_hidden(timeout=settings.default_timeout)
|
||||||
69
Joyhub_ui_auto_test/tests/test_login_logout.py
Normal file
69
Joyhub_ui_auto_test/tests/test_login_logout.py
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import allure
|
||||||
|
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__)
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("登录登出")
|
||||||
|
@allure.story("邮箱验证码登录")
|
||||||
|
@allure.title("校验用户登录成功后可退出登录")
|
||||||
|
def test_login_success_then_logout_wait_3s_and_close_browser(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("点击登录入口打开登录弹窗")
|
||||||
|
page.locator("aside button").first.click()
|
||||||
|
|
||||||
|
logger.info("动态获取登录弹窗输入框并输入邮箱: %s", settings.login_email)
|
||||||
|
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)
|
||||||
|
|
||||||
|
logger.info("输入验证码")
|
||||||
|
login_inputs.nth(1).fill(settings.verification_code)
|
||||||
|
|
||||||
|
logger.info("动态勾选登录确认项")
|
||||||
|
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()
|
||||||
|
|
||||||
|
logger.info("提交登录")
|
||||||
|
submit_button = page.locator("button").last
|
||||||
|
expect(submit_button).to_be_enabled(timeout=settings.default_timeout)
|
||||||
|
submit_button.click()
|
||||||
|
|
||||||
|
logger.info("等待登录成功后出现退出按钮")
|
||||||
|
logout_button = page.locator("aside button").first
|
||||||
|
expect(logout_button).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
|
||||||
|
logger.info("登录成功,停留 2 秒")
|
||||||
|
page.wait_for_timeout(2_000)
|
||||||
|
|
||||||
|
logger.info("点击 Logout 退出登录")
|
||||||
|
logout_button.click()
|
||||||
|
|
||||||
|
logger.info("校验退出登录成功后重新出现登录入口")
|
||||||
|
expect(page.locator("aside button").first).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
|
||||||
|
logger.info("退出登录成功,停留 3 秒")
|
||||||
|
page.wait_for_timeout(3_000)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(pytest.main([str(Path(__file__))]))
|
||||||
136
Joyhub_ui_auto_test/tests/test_my_order.py
Normal file
136
Joyhub_ui_auto_test/tests/test_my_order.py
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
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,
|
||||||
|
_first_visible,
|
||||||
|
_login_as_configured_user,
|
||||||
|
)
|
||||||
|
from utils.logger import get_logger
|
||||||
|
|
||||||
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
MY_ORDER_LINK_SELECTORS = [
|
||||||
|
'a[href*="order" i]',
|
||||||
|
'a:has-text("My Order")',
|
||||||
|
'a:has-text("My Orders")',
|
||||||
|
'button:has-text("My Order")',
|
||||||
|
'button:has-text("My Orders")',
|
||||||
|
'div.cursor-pointer:has-text("My Order")',
|
||||||
|
'div.cursor-pointer:has-text("My Orders")',
|
||||||
|
'li:has-text("My Order")',
|
||||||
|
'li:has-text("My Orders")',
|
||||||
|
'text=My Order',
|
||||||
|
'text=My Orders',
|
||||||
|
]
|
||||||
|
|
||||||
|
ORDER_DETAIL_LINK_SELECTORS = [
|
||||||
|
'a[href*="order" i]',
|
||||||
|
'button:has-text("Detail")',
|
||||||
|
'button:has-text("Details")',
|
||||||
|
'button:has-text("View")',
|
||||||
|
'button:has-text("View Detail")',
|
||||||
|
'button:has-text("View Details")',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def _click_first_visible_by_selectors(page, selectors, timeout=3_000):
|
||||||
|
for selector in selectors:
|
||||||
|
locator = page.locator(selector)
|
||||||
|
try:
|
||||||
|
if locator.count() == 0:
|
||||||
|
continue
|
||||||
|
candidate = _first_visible(locator)
|
||||||
|
expect(candidate).to_be_visible(timeout=timeout)
|
||||||
|
candidate.click()
|
||||||
|
return selector
|
||||||
|
except (AssertionError, PlaywrightTimeoutError):
|
||||||
|
continue
|
||||||
|
raise AssertionError(f"未找到可点击的可见元素: {selectors}")
|
||||||
|
|
||||||
|
|
||||||
|
def _wait_login_completed(page):
|
||||||
|
logger.info("等待登录完成并展示用户菜单入口")
|
||||||
|
page.wait_for_function(
|
||||||
|
"""
|
||||||
|
() => {
|
||||||
|
const visibleText = Array.from(document.querySelectorAll('a,button,div,li,span'))
|
||||||
|
.filter(element => !!(element.offsetWidth || element.offsetHeight || element.getClientRects().length))
|
||||||
|
.map(element => element.innerText || element.textContent || '')
|
||||||
|
.join(' ');
|
||||||
|
return /My Order|Logout|Create/i.test(visibleText) && !/^\\s*Login\\s*$/.test(visibleText);
|
||||||
|
}
|
||||||
|
""",
|
||||||
|
timeout=settings.default_timeout,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _open_my_order_from_home(page):
|
||||||
|
logger.info("从首页查找 My Order 入口")
|
||||||
|
try:
|
||||||
|
selector = _click_first_visible_by_selectors(page, MY_ORDER_LINK_SELECTORS)
|
||||||
|
logger.info("已通过首页可见入口进入 My Order: %s", selector)
|
||||||
|
return
|
||||||
|
except AssertionError:
|
||||||
|
logger.info("首页未直接展示 My Order,尝试点击用户侧边栏入口后继续查找")
|
||||||
|
|
||||||
|
aside_buttons = page.locator("aside button")
|
||||||
|
expect(aside_buttons.first).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
aside_buttons.first.click()
|
||||||
|
page.wait_for_timeout(1_000)
|
||||||
|
|
||||||
|
selector = _click_first_visible_by_selectors(page, MY_ORDER_LINK_SELECTORS, timeout=settings.default_timeout)
|
||||||
|
logger.info("已通过用户菜单进入 My Order: %s", selector)
|
||||||
|
|
||||||
|
|
||||||
|
def _open_first_order_detail(page):
|
||||||
|
logger.info("等待进入订单列表页")
|
||||||
|
expect(page).to_have_url(re.compile(r".*order.*", re.I), timeout=settings.default_timeout)
|
||||||
|
expect(page.get_by_text(re.compile(r"my order|orders?|order", re.I)).first).to_be_visible(
|
||||||
|
timeout=settings.default_timeout
|
||||||
|
)
|
||||||
|
|
||||||
|
logger.info("点击第一笔订单详情入口")
|
||||||
|
before_url = page.url
|
||||||
|
selector = _click_first_visible_by_selectors(page, ORDER_DETAIL_LINK_SELECTORS, timeout=settings.default_timeout)
|
||||||
|
logger.info("已点击订单详情入口: %s", selector)
|
||||||
|
|
||||||
|
try:
|
||||||
|
page.wait_for_url(lambda url: url != before_url, timeout=settings.default_timeout)
|
||||||
|
except PlaywrightTimeoutError:
|
||||||
|
logger.info("点击第一笔订单后 URL 未变化,继续校验当前页面是否展示详情内容")
|
||||||
|
|
||||||
|
expect(page.locator("body")).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
expect(page.get_by_text(re.compile(r"order|detail|status|total|payment|shipping", re.I)).first).to_be_visible(
|
||||||
|
timeout=settings.default_timeout
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("我的订单")
|
||||||
|
@allure.story("订单详情")
|
||||||
|
@allure.title("登录用户从首页进入 My Order 并查看第一笔订单详情")
|
||||||
|
def test_home_my_order_first_order_detail_after_login(page, ensure_logged_in_user):
|
||||||
|
logger.info("登录用户从首页进入 My Order 并查看第一笔订单详情")
|
||||||
|
logger.info("打开链接地址: %s", settings.base_url)
|
||||||
|
page.goto(settings.base_url, wait_until="domcontentloaded")
|
||||||
|
ensure_logged_in_user()
|
||||||
|
_wait_login_completed(page)
|
||||||
|
|
||||||
|
_open_my_order_from_home(page)
|
||||||
|
_open_first_order_detail(page)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(pytest.main([str(Path(__file__))]))
|
||||||
177
Joyhub_ui_auto_test/tests/test_navigation_pages.py
Normal file
177
Joyhub_ui_auto_test/tests/test_navigation_pages.py
Normal file
@@ -0,0 +1,177 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
import random
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import allure
|
||||||
|
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__)
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("导航")
|
||||||
|
@allure.story("顶部导航")
|
||||||
|
@allure.title("通过顶部导航进入 App 下载页并返回首页")
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("导航")
|
||||||
|
@allure.story("底部导航")
|
||||||
|
@allure.title("校验底部 Partnerships 和 FAQ 导航链接可用")
|
||||||
|
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)
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("导航")
|
||||||
|
@allure.story("About Us Blog")
|
||||||
|
@allure.title("从 About Us 进入 Blog 并随机浏览分类文章")
|
||||||
|
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}")
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("导航")
|
||||||
|
@allure.story("社交媒体链接")
|
||||||
|
@allure.title("校验底部社交媒体链接 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__))]))
|
||||||
32
Joyhub_ui_auto_test/tests/test_open_chrome_browser.py
Normal file
32
Joyhub_ui_auto_test/tests/test_open_chrome_browser.py
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import allure
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
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__)
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("浏览器")
|
||||||
|
@allure.story("Chromium启动")
|
||||||
|
@allure.title("打开 Chromium 浏览器访问首页并等待关闭")
|
||||||
|
def test_open_chromium_browser_wait_10s_then_close(page, ensure_guest_user):
|
||||||
|
logger.info("使用 pytest-playwright 统一无头浏览器配置")
|
||||||
|
|
||||||
|
logger.info("打开链接地址: %s", settings.base_url)
|
||||||
|
page.goto(settings.base_url)
|
||||||
|
ensure_guest_user()
|
||||||
|
|
||||||
|
logger.info("等待 10 秒")
|
||||||
|
page.wait_for_timeout(10_000)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(pytest.main([str(Path(__file__))]))
|
||||||
78
Joyhub_ui_auto_test/tests/test_partnerships_page.py
Normal file
78
Joyhub_ui_auto_test/tests/test_partnerships_page.py
Normal file
@@ -0,0 +1,78 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import allure
|
||||||
|
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__)
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("合作伙伴")
|
||||||
|
@allure.story("合作页内容")
|
||||||
|
@allure.title("校验 Partnerships 页面核心内容可见")
|
||||||
|
def test_partnerships_page_key_content_visible(page):
|
||||||
|
logger.info("使用 pytest-playwright 统一无头浏览器配置")
|
||||||
|
|
||||||
|
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)
|
||||||
|
assert page.title().strip()
|
||||||
|
expect(page.locator("body")).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
|
||||||
|
visible_headings_count = page.get_by_role("heading").count()
|
||||||
|
logger.info("当前 Partnerships 页面标题元素数量: %s", visible_headings_count)
|
||||||
|
assert visible_headings_count > 0
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("合作伙伴")
|
||||||
|
@allure.story("合作表单")
|
||||||
|
@allure.title("校验 Partnerships 合作表单字段可见且可编辑")
|
||||||
|
def test_partnerships_contact_form_fields_visible_and_editable(page):
|
||||||
|
logger.info("使用 pytest-playwright 统一无头浏览器配置")
|
||||||
|
|
||||||
|
logger.info("打开 Partnerships 页面")
|
||||||
|
page.goto("/partnerships", wait_until="domcontentloaded")
|
||||||
|
|
||||||
|
logger.info("动态校验合作表单字段可见并可输入")
|
||||||
|
form_inputs = page.locator('section input[type="text"]:not([readonly])')
|
||||||
|
form_textareas = page.locator("section textarea")
|
||||||
|
submit_button = page.locator("section button").last
|
||||||
|
|
||||||
|
name_input = form_inputs.nth(0)
|
||||||
|
email_input = form_inputs.nth(1)
|
||||||
|
business_input = form_inputs.nth(2)
|
||||||
|
collaboration_input = page.locator('section input[readonly]').first
|
||||||
|
message_input = form_textareas.first
|
||||||
|
|
||||||
|
expect(name_input).to_be_editable(timeout=settings.default_timeout)
|
||||||
|
expect(email_input).to_be_editable(timeout=settings.default_timeout)
|
||||||
|
expect(business_input).to_be_editable(timeout=settings.default_timeout)
|
||||||
|
expect(message_input).to_be_editable(timeout=settings.default_timeout)
|
||||||
|
|
||||||
|
name_input.fill("Joyhub Tester")
|
||||||
|
email_input.fill("tester@example.com")
|
||||||
|
business_input.fill("https://example.com")
|
||||||
|
message_input.fill("I want to explore product testing collaboration.")
|
||||||
|
|
||||||
|
expect(name_input).to_have_value("Joyhub Tester", timeout=settings.default_timeout)
|
||||||
|
expect(email_input).to_have_value("tester@example.com", timeout=settings.default_timeout)
|
||||||
|
expect(business_input).to_have_value("https://example.com", timeout=settings.default_timeout)
|
||||||
|
expect(collaboration_input).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
expect(collaboration_input).to_have_attribute("readonly", "", timeout=settings.default_timeout)
|
||||||
|
expect(message_input).to_have_value("I want to explore product testing collaboration.", timeout=settings.default_timeout)
|
||||||
|
expect(submit_button).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(pytest.main([str(Path(__file__))]))
|
||||||
159
Joyhub_ui_auto_test/tests/test_points_redemption_payment.py
Normal file
159
Joyhub_ui_auto_test/tests/test_points_redemption_payment.py
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
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__))]))
|
||||||
@@ -0,0 +1,167 @@
|
|||||||
|
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
|
||||||
|
|
||||||
|
from tests.conftest import accept_cookie_if_present, login_as_configured_user_if_needed
|
||||||
|
|
||||||
|
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 _accept_cookie_if_present(page):
|
||||||
|
accept_cookie_if_present(page)
|
||||||
|
|
||||||
|
|
||||||
|
def _first_visible(locator):
|
||||||
|
locator_count = locator.count()
|
||||||
|
for index in range(locator_count):
|
||||||
|
candidate = locator.nth(index)
|
||||||
|
if candidate.is_visible():
|
||||||
|
return candidate
|
||||||
|
raise AssertionError("未找到可见元素")
|
||||||
|
|
||||||
|
|
||||||
|
def _login_as_configured_user(page):
|
||||||
|
login_as_configured_user_if_needed(page)
|
||||||
|
|
||||||
|
|
||||||
|
def _add_random_shopping_product_to_cart(page):
|
||||||
|
logger.info("直接进入 Shopping 页面")
|
||||||
|
page.goto(settings.base_url.rstrip("/") + "/shopping", wait_until="domcontentloaded")
|
||||||
|
expect(page).to_have_url(re.compile(r".*/shopping/?$"), timeout=settings.default_timeout)
|
||||||
|
expect(page.locator("body")).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
|
||||||
|
logger.info("动态获取分类列表并随机选择商品加购")
|
||||||
|
category_buttons = page.locator("section > div:nth-of-type(1) > div:nth-of-type(2) > div:nth-of-type(1) button")
|
||||||
|
expect(category_buttons.first).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
category_count = category_buttons.count()
|
||||||
|
logger.info("当前分类数量: %s", category_count)
|
||||||
|
assert category_count > 0
|
||||||
|
|
||||||
|
category_indices = list(range(category_count))
|
||||||
|
random.shuffle(category_indices)
|
||||||
|
logger.info("随机分类尝试顺序: %s", category_indices)
|
||||||
|
|
||||||
|
last_error = None
|
||||||
|
for selected_category_index in category_indices:
|
||||||
|
logger.info("随机选择分类索引: %s", selected_category_index)
|
||||||
|
category_buttons.nth(selected_category_index).click()
|
||||||
|
page.wait_for_timeout(1_000)
|
||||||
|
|
||||||
|
logger.info("动态获取商品列表")
|
||||||
|
product_links = page.locator('section a[href^="/shopping/"][href*="selectedSkuId"]').evaluate_all(
|
||||||
|
"""
|
||||||
|
links => Array.from(new Map(
|
||||||
|
links
|
||||||
|
.map(link => link.getAttribute('href'))
|
||||||
|
.filter(Boolean)
|
||||||
|
.map(href => [href, href])
|
||||||
|
).values())
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
logger.info("当前可进入详情的商品数量: %s", len(product_links))
|
||||||
|
random.shuffle(product_links)
|
||||||
|
|
||||||
|
for selected_product_href in product_links:
|
||||||
|
try:
|
||||||
|
logger.info("尝试加购商品: %s", selected_product_href)
|
||||||
|
page.goto(settings.base_url.rstrip("/") + selected_product_href, wait_until="domcontentloaded")
|
||||||
|
expect(page).to_have_url(re.compile(r".*/shopping/.+selectedSkuId=.+"), timeout=settings.default_timeout)
|
||||||
|
expect(page.locator("body")).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
|
||||||
|
logger.info("动态获取商品规格行,逐行随机选择一个可用规格")
|
||||||
|
spec_rows = page.locator(".product-specs-scrollbar > div").filter(has=page.locator("button"))
|
||||||
|
expect(spec_rows.first).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
spec_row_count = spec_rows.count()
|
||||||
|
logger.info("当前规格行数量: %s", spec_row_count)
|
||||||
|
assert spec_row_count > 0
|
||||||
|
|
||||||
|
selected_spec_count = 0
|
||||||
|
for row_index in range(spec_row_count):
|
||||||
|
spec_options = spec_rows.nth(row_index).locator("button:not([disabled])")
|
||||||
|
spec_option_count = spec_options.count()
|
||||||
|
logger.info("规格行 %s 可选项数量: %s", row_index, spec_option_count)
|
||||||
|
if spec_option_count == 0:
|
||||||
|
continue
|
||||||
|
|
||||||
|
selected_spec_index = random.randrange(spec_option_count)
|
||||||
|
logger.info("规格行 %s 随机选择选项索引: %s", row_index, selected_spec_index)
|
||||||
|
spec_options.nth(selected_spec_index).click()
|
||||||
|
selected_spec_count += 1
|
||||||
|
page.wait_for_timeout(300)
|
||||||
|
|
||||||
|
assert selected_spec_count > 0
|
||||||
|
|
||||||
|
logger.info("动态点击数量增加按钮")
|
||||||
|
increase_quantity_button = page.locator("button:has(svg.lucide-plus):not([disabled])").first
|
||||||
|
try:
|
||||||
|
if increase_quantity_button.is_visible(timeout=3_000):
|
||||||
|
increase_click_count = random.randint(1, 3)
|
||||||
|
logger.info("随机增加商品数量次数: %s", increase_click_count)
|
||||||
|
for _ in range(increase_click_count):
|
||||||
|
increase_quantity_button.click()
|
||||||
|
page.wait_for_timeout(200)
|
||||||
|
except PlaywrightTimeoutError:
|
||||||
|
logger.info("当前商品未展示数量增加按钮,使用默认购买数量")
|
||||||
|
|
||||||
|
logger.info("动态获取加购按钮并点击")
|
||||||
|
add_to_cart_button = page.locator("button.bg-primary.text-white:not([disabled])").first
|
||||||
|
expect(add_to_cart_button).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
expect(add_to_cart_button).to_be_enabled(timeout=settings.default_timeout)
|
||||||
|
add_to_cart_button.click()
|
||||||
|
|
||||||
|
logger.info("校验购物车入口仍可见,表示加购流程已完成点击")
|
||||||
|
expect(page.locator('a[href="/view-cart"]').first).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
return
|
||||||
|
except (AssertionError, PlaywrightTimeoutError) as exc:
|
||||||
|
last_error = exc
|
||||||
|
logger.info("当前商品不可加购,继续尝试下一个商品: %s", exc)
|
||||||
|
page.goto(settings.base_url.rstrip("/") + "/shopping", wait_until="domcontentloaded")
|
||||||
|
expect(page).to_have_url(re.compile(r".*/shopping/?$"), timeout=settings.default_timeout)
|
||||||
|
category_buttons = page.locator(
|
||||||
|
"section > div:nth-of-type(1) > div:nth-of-type(2) > div:nth-of-type(1) button"
|
||||||
|
)
|
||||||
|
category_buttons.nth(selected_category_index).click()
|
||||||
|
page.wait_for_timeout(1_000)
|
||||||
|
|
||||||
|
raise AssertionError(f"未找到可加购的随机商品: {last_error}")
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("Rewards Shopping")
|
||||||
|
@allure.story("游客加购")
|
||||||
|
@allure.title("游客随机选择 Rewards Shopping 商品并加入购物车")
|
||||||
|
def test_rewards_shopping_random_product_add_to_cart_no_login(page, ensure_guest_user):
|
||||||
|
logger.info("使用游客身份执行 Rewards Shopping 随机商品加购")
|
||||||
|
logger.info("打开链接地址: %s", settings.base_url)
|
||||||
|
page.goto(settings.base_url, wait_until="domcontentloaded")
|
||||||
|
ensure_guest_user()
|
||||||
|
|
||||||
|
_add_random_shopping_product_to_cart(page)
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("Rewards Shopping")
|
||||||
|
@allure.story("登录用户加购")
|
||||||
|
@allure.title("登录用户随机选择 Rewards Shopping 商品并加入购物车")
|
||||||
|
def test_rewards_shopping_random_product_add_to_cart_after_login(page, ensure_logged_in_user):
|
||||||
|
logger.info("使用登录用户身份执行 Rewards Shopping 随机商品加购")
|
||||||
|
logger.info("打开链接地址: %s", settings.base_url)
|
||||||
|
page.goto(settings.base_url, wait_until="domcontentloaded")
|
||||||
|
ensure_logged_in_user()
|
||||||
|
|
||||||
|
_add_random_shopping_product_to_cart(page)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(pytest.main([str(Path(__file__))]))
|
||||||
278
Joyhub_ui_auto_test/tests/test_rewards_shopping_payment.py
Normal file
278
Joyhub_ui_auto_test/tests/test_rewards_shopping_payment.py
Normal file
@@ -0,0 +1,278 @@
|
|||||||
|
from pathlib import Path
|
||||||
|
import random
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import allure
|
||||||
|
import pytest
|
||||||
|
from playwright.sync_api import Error as PlaywrightError
|
||||||
|
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,
|
||||||
|
_first_visible,
|
||||||
|
_login_as_configured_user,
|
||||||
|
)
|
||||||
|
from utils.logger import get_logger
|
||||||
|
|
||||||
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
PAYPAL_EMAIL_SELECTORS = [
|
||||||
|
'input[name="login_email"]',
|
||||||
|
'input[name="email"]',
|
||||||
|
'input#email',
|
||||||
|
]
|
||||||
|
PAYPAL_PASSWORD_SELECTORS = [
|
||||||
|
'input[name="login_password"]',
|
||||||
|
'input[name="password"]',
|
||||||
|
'input#password',
|
||||||
|
]
|
||||||
|
PAYPAL_NEXT_SELECTORS = [
|
||||||
|
'button:has-text("Next")',
|
||||||
|
'input[type="submit"][value="Next"]',
|
||||||
|
'button#btnNext',
|
||||||
|
]
|
||||||
|
PAYPAL_LOGIN_SELECTORS = [
|
||||||
|
'button:has-text("Log In")',
|
||||||
|
'button:has-text("Log in")',
|
||||||
|
'button:has-text("Login")',
|
||||||
|
'button#btnLogin',
|
||||||
|
'input[type="submit"][value="Log In"]',
|
||||||
|
]
|
||||||
|
PAYPAL_PAY_SELECTORS = [
|
||||||
|
'button:has-text("Complete Purchase")',
|
||||||
|
'button:has-text("Pay Now")',
|
||||||
|
'button:has-text("Agree and Pay")',
|
||||||
|
'button:has-text("Continue")',
|
||||||
|
'button:has-text("Review Order")',
|
||||||
|
'input[type="submit"][value*="Pay"]',
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
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 _add_random_shopping_product_directly(page):
|
||||||
|
logger.info("直接进入 Shopping 页面并随机加购商品")
|
||||||
|
page.goto(settings.base_url.rstrip("/") + "/shopping", wait_until="domcontentloaded")
|
||||||
|
expect(page).to_have_url(re.compile(r".*/shopping/?$"), timeout=settings.default_timeout)
|
||||||
|
|
||||||
|
category_buttons = page.locator("section > div:nth-of-type(1) > div:nth-of-type(2) > div:nth-of-type(1) button")
|
||||||
|
expect(category_buttons.first).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
category_indices = list(range(category_buttons.count()))
|
||||||
|
random.shuffle(category_indices)
|
||||||
|
|
||||||
|
product_links = []
|
||||||
|
for selected_category_index in category_indices:
|
||||||
|
category_buttons.nth(selected_category_index).click()
|
||||||
|
page.wait_for_timeout(1_000)
|
||||||
|
product_links = page.locator('section a[href^="/shopping/"][href*="selectedSkuId"]').evaluate_all(
|
||||||
|
"""
|
||||||
|
links => Array.from(new Map(
|
||||||
|
links
|
||||||
|
.map(link => link.getAttribute('href'))
|
||||||
|
.filter(Boolean)
|
||||||
|
.map(href => [href, href])
|
||||||
|
).values())
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
if product_links:
|
||||||
|
break
|
||||||
|
|
||||||
|
assert product_links
|
||||||
|
selected_product_href = random.choice(product_links)
|
||||||
|
_first_visible(page.locator(f'section a[href="{selected_product_href}"]')).click()
|
||||||
|
expect(page).to_have_url(re.compile(r".*/shopping/.+selectedSkuId=.+"), timeout=settings.default_timeout)
|
||||||
|
|
||||||
|
spec_rows = page.locator(".product-specs-scrollbar > div").filter(has=page.locator("button"))
|
||||||
|
expect(spec_rows.first).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
selected_spec_count = 0
|
||||||
|
for row_index in range(spec_rows.count()):
|
||||||
|
spec_options = spec_rows.nth(row_index).locator("button:not([disabled])")
|
||||||
|
spec_option_count = spec_options.count()
|
||||||
|
if spec_option_count == 0:
|
||||||
|
continue
|
||||||
|
spec_options.nth(random.randrange(spec_option_count)).click()
|
||||||
|
selected_spec_count += 1
|
||||||
|
page.wait_for_timeout(300)
|
||||||
|
|
||||||
|
assert selected_spec_count > 0
|
||||||
|
increase_quantity_button = page.locator("button:has(svg.lucide-plus):not([disabled])").first
|
||||||
|
try:
|
||||||
|
if increase_quantity_button.is_visible(timeout=3_000):
|
||||||
|
for _ in range(random.randint(1, 3)):
|
||||||
|
increase_quantity_button.click()
|
||||||
|
page.wait_for_timeout(200)
|
||||||
|
except PlaywrightTimeoutError:
|
||||||
|
logger.info("当前商品未展示数量增加按钮,使用默认购买数量")
|
||||||
|
|
||||||
|
add_to_cart_button = page.locator("button.bg-primary.text-white:not([disabled])").first
|
||||||
|
expect(add_to_cart_button).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
expect(add_to_cart_button).to_be_enabled(timeout=settings.default_timeout)
|
||||||
|
add_to_cart_button.click()
|
||||||
|
expect(page.locator('a[href="/view-cart"]').first).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
|
||||||
|
|
||||||
|
def _go_to_cart(page):
|
||||||
|
logger.info("进入购物车页面")
|
||||||
|
page.goto(settings.base_url.rstrip("/") + "/view-cart", wait_until="domcontentloaded")
|
||||||
|
expect(page).to_have_url(re.compile(r".*/view-cart/?$"), timeout=settings.default_timeout)
|
||||||
|
expect(page.locator('iframe[title="PayPal-paypal"]').first).to_be_attached(timeout=settings.default_timeout)
|
||||||
|
|
||||||
|
|
||||||
|
def _add_random_one_or_more_products(page):
|
||||||
|
product_count = random.randint(1, 2)
|
||||||
|
logger.info("随机加入商品数量种类: %s", product_count)
|
||||||
|
for index in range(product_count):
|
||||||
|
logger.info("执行第 %s 次随机商品加购", index + 1)
|
||||||
|
_add_random_shopping_product_directly(page)
|
||||||
|
if index < product_count - 1:
|
||||||
|
page.goto(settings.base_url, wait_until="domcontentloaded")
|
||||||
|
|
||||||
|
|
||||||
|
def _trigger_paypal_payment(page):
|
||||||
|
logger.info("等待 PayPal 支付按钮渲染")
|
||||||
|
expect(page.locator('iframe[title="PayPal-paypal"]').first).to_be_attached(timeout=settings.default_timeout)
|
||||||
|
page.wait_for_timeout(3_000)
|
||||||
|
|
||||||
|
logger.info("坐标点击页面主 DOM 中可见的 PayPal 按钮")
|
||||||
|
paypal_buttons = page.locator('button[class*="FFCE0C"]')
|
||||||
|
for index in range(paypal_buttons.count()):
|
||||||
|
paypal_button = paypal_buttons.nth(index)
|
||||||
|
try:
|
||||||
|
if not paypal_button.is_visible(timeout=1_000):
|
||||||
|
continue
|
||||||
|
if not paypal_button.is_enabled(timeout=1_000):
|
||||||
|
continue
|
||||||
|
|
||||||
|
box = paypal_button.bounding_box()
|
||||||
|
if not box:
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
with page.expect_popup(timeout=10_000) as popup_info:
|
||||||
|
page.mouse.click(box["x"] + box["width"] / 2, box["y"] + box["height"] / 2)
|
||||||
|
paypal_page = popup_info.value
|
||||||
|
except PlaywrightTimeoutError:
|
||||||
|
logger.info("未捕获到 PayPal 弹窗,检查当前页是否已跳转")
|
||||||
|
page.wait_for_timeout(3_000)
|
||||||
|
if "paypal" in page.url.lower():
|
||||||
|
paypal_page = page
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
|
||||||
|
try:
|
||||||
|
paypal_page.wait_for_load_state("domcontentloaded", timeout=settings.default_timeout)
|
||||||
|
try:
|
||||||
|
paypal_page.wait_for_url(re.compile(r".*paypal.*"), timeout=settings.default_timeout)
|
||||||
|
except PlaywrightTimeoutError:
|
||||||
|
logger.info("PayPal 页面当前地址未包含 paypal: %s", paypal_page.url)
|
||||||
|
expect(paypal_page.locator("body")).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
return paypal_page
|
||||||
|
except PlaywrightError as exc:
|
||||||
|
logger.info("PayPal 弹窗已被触发但提前关闭: %s", exc)
|
||||||
|
return None
|
||||||
|
except PlaywrightTimeoutError:
|
||||||
|
logger.info("当前 PayPal 按钮未触发支付页,继续尝试下一个按钮")
|
||||||
|
|
||||||
|
raise AssertionError("未找到可点击并能打开支付页的 PayPal 按钮")
|
||||||
|
|
||||||
|
|
||||||
|
def _login_paypal_if_required(paypal_page):
|
||||||
|
logger.info("处理 PayPal 登录页面")
|
||||||
|
try:
|
||||||
|
email_input = _visible_locator(paypal_page, PAYPAL_EMAIL_SELECTORS)
|
||||||
|
except AssertionError:
|
||||||
|
logger.info("PayPal 当前页面未出现邮箱输入框,可能已保持登录态")
|
||||||
|
return
|
||||||
|
|
||||||
|
email_input.fill(settings.paypal_email)
|
||||||
|
|
||||||
|
try:
|
||||||
|
next_button = _visible_locator(paypal_page, PAYPAL_NEXT_SELECTORS, timeout=3_000)
|
||||||
|
next_button.click()
|
||||||
|
except AssertionError:
|
||||||
|
logger.info("PayPal 未出现 Next 按钮,继续查找密码输入框")
|
||||||
|
|
||||||
|
password_input = _visible_locator(paypal_page, PAYPAL_PASSWORD_SELECTORS)
|
||||||
|
password_input.fill(settings.paypal_password)
|
||||||
|
|
||||||
|
login_button = _visible_locator(paypal_page, PAYPAL_LOGIN_SELECTORS)
|
||||||
|
expect(login_button).to_be_enabled(timeout=settings.default_timeout)
|
||||||
|
login_button.click()
|
||||||
|
paypal_page.wait_for_load_state("domcontentloaded", timeout=settings.default_timeout)
|
||||||
|
|
||||||
|
|
||||||
|
def _complete_paypal_payment(page, paypal_page):
|
||||||
|
logger.info("在 PayPal 页面确认支付")
|
||||||
|
pay_button = _visible_locator(paypal_page, PAYPAL_PAY_SELECTORS, timeout=settings.default_timeout)
|
||||||
|
expect(pay_button).to_be_enabled(timeout=settings.default_timeout)
|
||||||
|
pay_button.click()
|
||||||
|
|
||||||
|
logger.info("等待 PayPal 支付完成并返回商户站点")
|
||||||
|
try:
|
||||||
|
paypal_page.wait_for_close(timeout=settings.default_timeout)
|
||||||
|
except PlaywrightTimeoutError:
|
||||||
|
logger.info("PayPal 弹窗未自动关闭,继续等待主页面跳转")
|
||||||
|
|
||||||
|
page.wait_for_load_state("domcontentloaded", timeout=settings.default_timeout)
|
||||||
|
expect(page).to_have_url(re.compile(r".*joyhub-website-frontend-test.*"), timeout=settings.default_timeout)
|
||||||
|
|
||||||
|
success_text = page.get_by_text(re.compile(r"success|paid|payment|order", re.I)).first
|
||||||
|
expect(success_text).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
|
||||||
|
|
||||||
|
def _pay_random_shopping_products(page):
|
||||||
|
_add_random_one_or_more_products(page)
|
||||||
|
_go_to_cart(page)
|
||||||
|
paypal_page = _trigger_paypal_payment(page)
|
||||||
|
|
||||||
|
if not settings.run_paypal_payment:
|
||||||
|
logger.info("RUN_PAYPAL_PAYMENT 未开启,仅校验支付入口可触发")
|
||||||
|
expect(page).to_have_url(re.compile(r".*/view-cart/?$"), timeout=settings.default_timeout)
|
||||||
|
return
|
||||||
|
|
||||||
|
assert paypal_page is not None, "PayPal 弹窗已触发但提前关闭,无法继续真实付款"
|
||||||
|
_login_paypal_if_required(paypal_page)
|
||||||
|
_complete_paypal_payment(page, paypal_page)
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("Rewards Shopping")
|
||||||
|
@allure.story("游客支付")
|
||||||
|
@allure.title("游客随机选择 Rewards Shopping 商品并触发 PayPal 支付")
|
||||||
|
def test_rewards_shopping_random_products_payment_no_login(page, ensure_guest_user):
|
||||||
|
logger.info("使用游客身份执行随机商品 PayPal 支付")
|
||||||
|
page.goto(settings.base_url, wait_until="domcontentloaded")
|
||||||
|
ensure_guest_user()
|
||||||
|
|
||||||
|
_pay_random_shopping_products(page)
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("Rewards Shopping")
|
||||||
|
@allure.story("登录用户支付")
|
||||||
|
@allure.title("登录用户随机选择 Rewards Shopping 商品并触发 PayPal 支付")
|
||||||
|
def test_rewards_shopping_random_products_payment_after_login(page, ensure_logged_in_user):
|
||||||
|
logger.info("使用登录用户身份执行随机商品 PayPal 支付")
|
||||||
|
page.goto(settings.base_url, wait_until="domcontentloaded")
|
||||||
|
ensure_logged_in_user()
|
||||||
|
|
||||||
|
_pay_random_shopping_products(page)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(pytest.main([str(Path(__file__))]))
|
||||||
@@ -0,0 +1,192 @@
|
|||||||
|
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 utils.logger import get_logger
|
||||||
|
|
||||||
|
logger = get_logger(__name__)
|
||||||
|
|
||||||
|
LANGUAGE_OPTIONS = ["English", "Français"]
|
||||||
|
|
||||||
|
|
||||||
|
def _visible_header(page):
|
||||||
|
headers = page.locator("header")
|
||||||
|
for index in range(headers.count()):
|
||||||
|
header = headers.nth(index)
|
||||||
|
try:
|
||||||
|
if header.is_visible(timeout=1_000):
|
||||||
|
return header
|
||||||
|
except PlaywrightTimeoutError:
|
||||||
|
continue
|
||||||
|
raise AssertionError("未找到可见的页面头部")
|
||||||
|
|
||||||
|
|
||||||
|
def _visible_dropdown_options(page):
|
||||||
|
return page.locator('div[class*="hover:bg-grey700"]').filter(visible=True)
|
||||||
|
|
||||||
|
|
||||||
|
def _select_random_language(page):
|
||||||
|
header = _visible_header(page)
|
||||||
|
language_trigger = header.locator("div.cursor-pointer").nth(3)
|
||||||
|
expect(language_trigger).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
language_trigger.click()
|
||||||
|
|
||||||
|
options = _visible_dropdown_options(page)
|
||||||
|
available_languages = []
|
||||||
|
for index in range(options.count()):
|
||||||
|
option_text = options.nth(index).inner_text(timeout=3_000).strip()
|
||||||
|
if option_text in LANGUAGE_OPTIONS:
|
||||||
|
available_languages.append(option_text)
|
||||||
|
|
||||||
|
assert available_languages, "语言下拉没有可选项"
|
||||||
|
selected_language = random.choice(available_languages)
|
||||||
|
logger.info("随机选择语言: %s,可选语言: %s", selected_language, available_languages)
|
||||||
|
options.filter(has_text=re.compile(rf"^{re.escape(selected_language)}$")).first.click()
|
||||||
|
page.wait_for_load_state("domcontentloaded", timeout=settings.default_timeout)
|
||||||
|
page.wait_for_timeout(1_000)
|
||||||
|
return selected_language
|
||||||
|
|
||||||
|
|
||||||
|
def _select_random_country(page):
|
||||||
|
header = _visible_header(page)
|
||||||
|
country_trigger = header.locator("div.cursor-pointer").nth(4)
|
||||||
|
expect(country_trigger).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
country_trigger.click()
|
||||||
|
|
||||||
|
options = _visible_dropdown_options(page)
|
||||||
|
expect(options.first).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
countries = []
|
||||||
|
for index in range(options.count()):
|
||||||
|
country_text = options.nth(index).inner_text(timeout=3_000).strip()
|
||||||
|
if country_text and country_text not in LANGUAGE_OPTIONS:
|
||||||
|
countries.append(country_text)
|
||||||
|
|
||||||
|
assert countries, "国家下拉没有可选项"
|
||||||
|
selected_country = random.choice(countries)
|
||||||
|
logger.info("随机选择国家: %s,可选国家数量: %s", selected_country, len(countries))
|
||||||
|
options.filter(has_text=re.compile(rf"^{re.escape(selected_country)}$")).first.click()
|
||||||
|
page.wait_for_load_state("domcontentloaded", timeout=settings.default_timeout)
|
||||||
|
page.wait_for_timeout(1_000)
|
||||||
|
return selected_country
|
||||||
|
|
||||||
|
|
||||||
|
def _shopping_product_links(page):
|
||||||
|
return page.locator('section a[href^="/shopping/"][href*="selectedSkuId"]').evaluate_all(
|
||||||
|
"""
|
||||||
|
links => Array.from(new Map(
|
||||||
|
links
|
||||||
|
.map(link => link.getAttribute('href'))
|
||||||
|
.filter(Boolean)
|
||||||
|
.map(href => [href, href])
|
||||||
|
).values())
|
||||||
|
"""
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _find_random_product_href_or_none(page):
|
||||||
|
logger.info("进入 Shopping 页面,查找当前国家可选商品")
|
||||||
|
page.goto(settings.base_url.rstrip("/") + "/shopping", wait_until="domcontentloaded")
|
||||||
|
expect(page).to_have_url(re.compile(r".*/shopping/?$"), timeout=settings.default_timeout)
|
||||||
|
expect(page.locator("body")).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
page.wait_for_timeout(2_000)
|
||||||
|
|
||||||
|
category_buttons = page.locator("section > div:nth-of-type(1) > div:nth-of-type(2) > div:nth-of-type(1) button")
|
||||||
|
try:
|
||||||
|
if not category_buttons.first.is_visible(timeout=5_000):
|
||||||
|
logger.info("当前国家 Shopping 页面无分类,认为没有商品可选")
|
||||||
|
return None
|
||||||
|
except PlaywrightTimeoutError:
|
||||||
|
logger.info("当前国家 Shopping 页面未加载到分类,认为没有商品可选")
|
||||||
|
return None
|
||||||
|
|
||||||
|
category_indices = list(range(category_buttons.count()))
|
||||||
|
random.shuffle(category_indices)
|
||||||
|
logger.info("随机分类尝试顺序: %s", category_indices)
|
||||||
|
|
||||||
|
for category_index in category_indices:
|
||||||
|
category_buttons.nth(category_index).click()
|
||||||
|
page.wait_for_timeout(1_000)
|
||||||
|
product_links = _shopping_product_links(page)
|
||||||
|
logger.info("分类索引 %s 可进入详情的商品数量: %s", category_index, len(product_links))
|
||||||
|
if product_links:
|
||||||
|
return random.choice(product_links)
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def _add_product_to_cart(page, product_href):
|
||||||
|
logger.info("进入随机商品详情并加购: %s", product_href)
|
||||||
|
page.goto(settings.base_url.rstrip("/") + product_href, wait_until="domcontentloaded")
|
||||||
|
expect(page).to_have_url(re.compile(r".*/shopping/.+selectedSkuId=.+"), timeout=settings.default_timeout)
|
||||||
|
expect(page.locator("body")).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
|
||||||
|
spec_rows = page.locator(".product-specs-scrollbar > div").filter(has=page.locator("button"))
|
||||||
|
expect(spec_rows.first).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
|
||||||
|
selected_spec_count = 0
|
||||||
|
for row_index in range(spec_rows.count()):
|
||||||
|
spec_options = spec_rows.nth(row_index).locator("button:not([disabled])")
|
||||||
|
spec_option_count = spec_options.count()
|
||||||
|
if spec_option_count == 0:
|
||||||
|
continue
|
||||||
|
selected_spec_index = random.randrange(spec_option_count)
|
||||||
|
logger.info("规格行 %s 随机选择选项索引: %s", row_index, selected_spec_index)
|
||||||
|
spec_options.nth(selected_spec_index).click()
|
||||||
|
selected_spec_count += 1
|
||||||
|
page.wait_for_timeout(300)
|
||||||
|
|
||||||
|
assert selected_spec_count > 0, "商品详情没有可选规格"
|
||||||
|
|
||||||
|
increase_quantity_button = page.locator("button:has(svg.lucide-plus):not([disabled])").first
|
||||||
|
try:
|
||||||
|
if increase_quantity_button.is_visible(timeout=3_000):
|
||||||
|
increase_click_count = random.randint(1, 3)
|
||||||
|
logger.info("随机增加商品数量次数: %s", increase_click_count)
|
||||||
|
for _ in range(increase_click_count):
|
||||||
|
increase_quantity_button.click()
|
||||||
|
page.wait_for_timeout(200)
|
||||||
|
except PlaywrightTimeoutError:
|
||||||
|
logger.info("当前商品未展示数量增加按钮,使用默认购买数量")
|
||||||
|
|
||||||
|
add_to_cart_button = page.locator("button.bg-primary.text-white:not([disabled])").first
|
||||||
|
expect(add_to_cart_button).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
expect(add_to_cart_button).to_be_enabled(timeout=settings.default_timeout)
|
||||||
|
add_to_cart_button.click()
|
||||||
|
|
||||||
|
expect(page.locator('a[href="/view-cart"]').first).to_be_visible(timeout=settings.default_timeout)
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("Shopping")
|
||||||
|
@allure.story("语言国家切换")
|
||||||
|
@allure.title("随机切换语言和国家后选择 Shopping 商品加入购物车")
|
||||||
|
def test_switch_random_language_country_then_add_shopping_product_to_cart(page, ensure_guest_user):
|
||||||
|
logger.info("打开 JoyHub 首页并确保游客身份")
|
||||||
|
page.goto(settings.base_url, wait_until="domcontentloaded")
|
||||||
|
ensure_guest_user()
|
||||||
|
|
||||||
|
selected_language = _select_random_language(page)
|
||||||
|
selected_country = _select_random_country(page)
|
||||||
|
|
||||||
|
product_href = _find_random_product_href_or_none(page)
|
||||||
|
if not product_href:
|
||||||
|
logger.info("语言 %s / 国家 %s 没有商品可选,用例按预期通过", selected_language, selected_country)
|
||||||
|
assert True
|
||||||
|
return
|
||||||
|
|
||||||
|
_add_product_to_cart(page, product_href)
|
||||||
|
logger.info("语言 %s / 国家 %s 商品加购成功", selected_language, selected_country)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
raise SystemExit(pytest.main([str(Path(__file__))]))
|
||||||
38
Joyhub_ui_auto_test/tmp_probe_points.py
Normal file
38
Joyhub_ui_auto_test/tmp_probe_points.py
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
from playwright.sync_api import sync_playwright
|
||||||
|
|
||||||
|
base = 'https://joyhub-website-frontend-test.best-envision.com'
|
||||||
|
countries = [
|
||||||
|
'Kenya',
|
||||||
|
'Côte d’ivoire',
|
||||||
|
'South Korea',
|
||||||
|
'Great Britain (United Kingdom; England)',
|
||||||
|
'Vatican City (The Holy See)',
|
||||||
|
'Singapore',
|
||||||
|
'Sweden',
|
||||||
|
'Poland',
|
||||||
|
'Netherlands',
|
||||||
|
'Japan',
|
||||||
|
'Italy',
|
||||||
|
'Spain',
|
||||||
|
'Germany',
|
||||||
|
'Canada',
|
||||||
|
'Australia',
|
||||||
|
'France',
|
||||||
|
]
|
||||||
|
|
||||||
|
with sync_playwright() as p:
|
||||||
|
browser = p.chromium.launch(headless=True)
|
||||||
|
page = browser.new_page(viewport={'width': 1920, 'height': 1080})
|
||||||
|
for country in countries:
|
||||||
|
try:
|
||||||
|
page.goto(base + '/points-redemption', wait_until='domcontentloaded')
|
||||||
|
page.wait_for_timeout(1500)
|
||||||
|
page.locator('header .relative.inline-block').nth(5).click(force=True)
|
||||||
|
page.wait_for_timeout(500)
|
||||||
|
page.get_by_text(country, exact=True).first.click(force=True, timeout=5000)
|
||||||
|
page.wait_for_timeout(2500)
|
||||||
|
body = page.locator('body').inner_text()
|
||||||
|
print(country, '| url=', page.url, '| redeem=', 'Redeem' in body, '| unsupported=', 'currently do not support delivery' in body, '| sample=', body[:300].replace('\n', ' | '))
|
||||||
|
except Exception as exc:
|
||||||
|
print(country, '| ERROR=', type(exc).__name__, str(exc)[:200])
|
||||||
|
browser.close()
|
||||||
25
Joyhub_ui_auto_test/utils/logger.py
Normal file
25
Joyhub_ui_auto_test/utils/logger.py
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
import logging
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
|
||||||
|
REPORTS_DIR = Path(__file__).resolve().parents[1] / "reports"
|
||||||
|
LOG_FILE = REPORTS_DIR / "test_run.log"
|
||||||
|
|
||||||
|
|
||||||
|
def get_logger(name: str = "ui-test") -> logging.Logger:
|
||||||
|
REPORTS_DIR.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
logger = logging.getLogger(name)
|
||||||
|
if not logger.handlers:
|
||||||
|
formatter = logging.Formatter("%(asctime)s [%(levelname)s] %(name)s - %(message)s")
|
||||||
|
|
||||||
|
stream_handler = logging.StreamHandler()
|
||||||
|
stream_handler.setFormatter(formatter)
|
||||||
|
logger.addHandler(stream_handler)
|
||||||
|
|
||||||
|
file_handler = logging.FileHandler(LOG_FILE, encoding="utf-8")
|
||||||
|
file_handler.setFormatter(formatter)
|
||||||
|
logger.addHandler(file_handler)
|
||||||
|
|
||||||
|
logger.setLevel(logging.INFO)
|
||||||
|
return logger
|
||||||
202
Joyhub_ui_auto_test/webapp-testing/LICENSE.txt
Normal file
202
Joyhub_ui_auto_test/webapp-testing/LICENSE.txt
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright 2026 Anthropic, PBC.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
96
Joyhub_ui_auto_test/webapp-testing/SKILL.md
Normal file
96
Joyhub_ui_auto_test/webapp-testing/SKILL.md
Normal file
@@ -0,0 +1,96 @@
|
|||||||
|
---
|
||||||
|
name: webapp-testing
|
||||||
|
description: Toolkit for interacting with and testing local web applications using Playwright. Supports verifying frontend functionality, debugging UI behavior, capturing browser screenshots, and viewing browser logs.
|
||||||
|
license: Complete terms in LICENSE.txt
|
||||||
|
---
|
||||||
|
|
||||||
|
# Web Application Testing
|
||||||
|
|
||||||
|
To test local web applications, write native Python Playwright scripts.
|
||||||
|
|
||||||
|
**Helper Scripts Available**:
|
||||||
|
- `scripts/with_server.py` - Manages server lifecycle (supports multiple servers)
|
||||||
|
|
||||||
|
**Always run scripts with `--help` first** to see usage. DO NOT read the source until you try running the script first and find that a customized solution is abslutely necessary. These scripts can be very large and thus pollute your context window. They exist to be called directly as black-box scripts rather than ingested into your context window.
|
||||||
|
|
||||||
|
## Decision Tree: Choosing Your Approach
|
||||||
|
|
||||||
|
```
|
||||||
|
User task → Is it static HTML?
|
||||||
|
├─ Yes → Read HTML file directly to identify selectors
|
||||||
|
│ ├─ Success → Write Playwright script using selectors
|
||||||
|
│ └─ Fails/Incomplete → Treat as dynamic (below)
|
||||||
|
│
|
||||||
|
└─ No (dynamic webapp) → Is the server already running?
|
||||||
|
├─ No → Run: python scripts/with_server.py --help
|
||||||
|
│ Then use the helper + write simplified Playwright script
|
||||||
|
│
|
||||||
|
└─ Yes → Reconnaissance-then-action:
|
||||||
|
1. Navigate and wait for networkidle
|
||||||
|
2. Take screenshot or inspect DOM
|
||||||
|
3. Identify selectors from rendered state
|
||||||
|
4. Execute actions with discovered selectors
|
||||||
|
```
|
||||||
|
|
||||||
|
## Example: Using with_server.py
|
||||||
|
|
||||||
|
To start a server, run `--help` first, then use the helper:
|
||||||
|
|
||||||
|
**Single server:**
|
||||||
|
```bash
|
||||||
|
python scripts/with_server.py --server "npm run dev" --port 5173 -- python your_automation.py
|
||||||
|
```
|
||||||
|
|
||||||
|
**Multiple servers (e.g., backend + frontend):**
|
||||||
|
```bash
|
||||||
|
python scripts/with_server.py \
|
||||||
|
--server "cd backend && python server.py" --port 3000 \
|
||||||
|
--server "cd frontend && npm run dev" --port 5173 \
|
||||||
|
-- python your_automation.py
|
||||||
|
```
|
||||||
|
|
||||||
|
To create an automation script, include only Playwright logic (servers are managed automatically):
|
||||||
|
```python
|
||||||
|
from playwright.sync_api import sync_playwright
|
||||||
|
|
||||||
|
with sync_playwright() as p:
|
||||||
|
browser = p.chromium.launch(headless=True) # Always launch chromium in headless mode
|
||||||
|
page = browser.new_page()
|
||||||
|
page.goto('http://localhost:5173') # Server already running and ready
|
||||||
|
page.wait_for_load_state('networkidle') # CRITICAL: Wait for JS to execute
|
||||||
|
# ... your automation logic
|
||||||
|
browser.close()
|
||||||
|
```
|
||||||
|
|
||||||
|
## Reconnaissance-Then-Action Pattern
|
||||||
|
|
||||||
|
1. **Inspect rendered DOM**:
|
||||||
|
```python
|
||||||
|
page.screenshot(path='/tmp/inspect.png', full_page=True)
|
||||||
|
content = page.content()
|
||||||
|
page.locator('button').all()
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Identify selectors** from inspection results
|
||||||
|
|
||||||
|
3. **Execute actions** using discovered selectors
|
||||||
|
|
||||||
|
## Common Pitfall
|
||||||
|
|
||||||
|
❌ **Don't** inspect the DOM before waiting for `networkidle` on dynamic apps
|
||||||
|
✅ **Do** wait for `page.wait_for_load_state('networkidle')` before inspection
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
- **Use bundled scripts as black boxes** - To accomplish a task, consider whether one of the scripts available in `scripts/` can help. These scripts handle common, complex workflows reliably without cluttering the context window. Use `--help` to see usage, then invoke directly.
|
||||||
|
- Use `sync_playwright()` for synchronous scripts
|
||||||
|
- Always close the browser when done
|
||||||
|
- Use descriptive selectors: `text=`, `role=`, CSS selectors, or IDs
|
||||||
|
- Add appropriate waits: `page.wait_for_selector()` or `page.wait_for_timeout()`
|
||||||
|
|
||||||
|
## Reference Files
|
||||||
|
|
||||||
|
- **examples/** - Examples showing common patterns:
|
||||||
|
- `element_discovery.py` - Discovering buttons, links, and inputs on a page
|
||||||
|
- `static_html_automation.py` - Using file:// URLs for local HTML
|
||||||
|
- `console_logging.py` - Capturing console logs during automation
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
from playwright.sync_api import sync_playwright
|
||||||
|
|
||||||
|
# Example: Capturing console logs during browser automation
|
||||||
|
|
||||||
|
url = 'http://localhost:5173' # Replace with your URL
|
||||||
|
|
||||||
|
console_logs = []
|
||||||
|
|
||||||
|
with sync_playwright() as p:
|
||||||
|
browser = p.chromium.launch(headless=True)
|
||||||
|
page = browser.new_page(viewport={'width': 1920, 'height': 1080})
|
||||||
|
|
||||||
|
# Set up console log capture
|
||||||
|
def handle_console_message(msg):
|
||||||
|
console_logs.append(f"[{msg.type}] {msg.text}")
|
||||||
|
print(f"Console: [{msg.type}] {msg.text}")
|
||||||
|
|
||||||
|
page.on("console", handle_console_message)
|
||||||
|
|
||||||
|
# Navigate to page
|
||||||
|
page.goto(url)
|
||||||
|
page.wait_for_load_state('networkidle')
|
||||||
|
|
||||||
|
# Interact with the page (triggers console logs)
|
||||||
|
page.click('text=Dashboard')
|
||||||
|
page.wait_for_timeout(1000)
|
||||||
|
|
||||||
|
browser.close()
|
||||||
|
|
||||||
|
# Save console logs to file
|
||||||
|
with open('/mnt/user-data/outputs/console.log', 'w') as f:
|
||||||
|
f.write('\n'.join(console_logs))
|
||||||
|
|
||||||
|
print(f"\nCaptured {len(console_logs)} console messages")
|
||||||
|
print(f"Logs saved to: /mnt/user-data/outputs/console.log")
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
from playwright.sync_api import sync_playwright
|
||||||
|
|
||||||
|
# Example: Discovering buttons and other elements on a page
|
||||||
|
|
||||||
|
with sync_playwright() as p:
|
||||||
|
browser = p.chromium.launch(headless=True)
|
||||||
|
page = browser.new_page()
|
||||||
|
|
||||||
|
# Navigate to page and wait for it to fully load
|
||||||
|
page.goto('http://localhost:5173')
|
||||||
|
page.wait_for_load_state('networkidle')
|
||||||
|
|
||||||
|
# Discover all buttons on the page
|
||||||
|
buttons = page.locator('button').all()
|
||||||
|
print(f"Found {len(buttons)} buttons:")
|
||||||
|
for i, button in enumerate(buttons):
|
||||||
|
text = button.inner_text() if button.is_visible() else "[hidden]"
|
||||||
|
print(f" [{i}] {text}")
|
||||||
|
|
||||||
|
# Discover links
|
||||||
|
links = page.locator('a[href]').all()
|
||||||
|
print(f"\nFound {len(links)} links:")
|
||||||
|
for link in links[:5]: # Show first 5
|
||||||
|
text = link.inner_text().strip()
|
||||||
|
href = link.get_attribute('href')
|
||||||
|
print(f" - {text} -> {href}")
|
||||||
|
|
||||||
|
# Discover input fields
|
||||||
|
inputs = page.locator('input, textarea, select').all()
|
||||||
|
print(f"\nFound {len(inputs)} input fields:")
|
||||||
|
for input_elem in inputs:
|
||||||
|
name = input_elem.get_attribute('name') or input_elem.get_attribute('id') or "[unnamed]"
|
||||||
|
input_type = input_elem.get_attribute('type') or 'text'
|
||||||
|
print(f" - {name} ({input_type})")
|
||||||
|
|
||||||
|
# Take screenshot for visual reference
|
||||||
|
page.screenshot(path='/tmp/page_discovery.png', full_page=True)
|
||||||
|
print("\nScreenshot saved to /tmp/page_discovery.png")
|
||||||
|
|
||||||
|
browser.close()
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
from playwright.sync_api import sync_playwright
|
||||||
|
import os
|
||||||
|
|
||||||
|
# Example: Automating interaction with static HTML files using file:// URLs
|
||||||
|
|
||||||
|
html_file_path = os.path.abspath('path/to/your/file.html')
|
||||||
|
file_url = f'file://{html_file_path}'
|
||||||
|
|
||||||
|
with sync_playwright() as p:
|
||||||
|
browser = p.chromium.launch(headless=True)
|
||||||
|
page = browser.new_page(viewport={'width': 1920, 'height': 1080})
|
||||||
|
|
||||||
|
# Navigate to local HTML file
|
||||||
|
page.goto(file_url)
|
||||||
|
|
||||||
|
# Take screenshot
|
||||||
|
page.screenshot(path='/mnt/user-data/outputs/static_page.png', full_page=True)
|
||||||
|
|
||||||
|
# Interact with elements
|
||||||
|
page.click('text=Click Me')
|
||||||
|
page.fill('#name', 'John Doe')
|
||||||
|
page.fill('#email', 'john@example.com')
|
||||||
|
|
||||||
|
# Submit form
|
||||||
|
page.click('button[type="submit"]')
|
||||||
|
page.wait_for_timeout(500)
|
||||||
|
|
||||||
|
# Take final screenshot
|
||||||
|
page.screenshot(path='/mnt/user-data/outputs/after_submit.png', full_page=True)
|
||||||
|
|
||||||
|
browser.close()
|
||||||
|
|
||||||
|
print("Static HTML automation completed!")
|
||||||
106
Joyhub_ui_auto_test/webapp-testing/scripts/with_server.py
Normal file
106
Joyhub_ui_auto_test/webapp-testing/scripts/with_server.py
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""
|
||||||
|
Start one or more servers, wait for them to be ready, run a command, then clean up.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
# Single server
|
||||||
|
python scripts/with_server.py --server "npm run dev" --port 5173 -- python automation.py
|
||||||
|
python scripts/with_server.py --server "npm start" --port 3000 -- python test.py
|
||||||
|
|
||||||
|
# Multiple servers
|
||||||
|
python scripts/with_server.py \
|
||||||
|
--server "cd backend && python server.py" --port 3000 \
|
||||||
|
--server "cd frontend && npm run dev" --port 5173 \
|
||||||
|
-- python test.py
|
||||||
|
"""
|
||||||
|
|
||||||
|
import subprocess
|
||||||
|
import socket
|
||||||
|
import time
|
||||||
|
import sys
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
def is_server_ready(port, timeout=30):
|
||||||
|
"""Wait for server to be ready by polling the port."""
|
||||||
|
start_time = time.time()
|
||||||
|
while time.time() - start_time < timeout:
|
||||||
|
try:
|
||||||
|
with socket.create_connection(('localhost', port), timeout=1):
|
||||||
|
return True
|
||||||
|
except (socket.error, ConnectionRefusedError):
|
||||||
|
time.sleep(0.5)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
parser = argparse.ArgumentParser(description='Run command with one or more servers')
|
||||||
|
parser.add_argument('--server', action='append', dest='servers', required=True, help='Server command (can be repeated)')
|
||||||
|
parser.add_argument('--port', action='append', dest='ports', type=int, required=True, help='Port for each server (must match --server count)')
|
||||||
|
parser.add_argument('--timeout', type=int, default=30, help='Timeout in seconds per server (default: 30)')
|
||||||
|
parser.add_argument('command', nargs=argparse.REMAINDER, help='Command to run after server(s) ready')
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
# Remove the '--' separator if present
|
||||||
|
if args.command and args.command[0] == '--':
|
||||||
|
args.command = args.command[1:]
|
||||||
|
|
||||||
|
if not args.command:
|
||||||
|
print("Error: No command specified to run")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# Parse server configurations
|
||||||
|
if len(args.servers) != len(args.ports):
|
||||||
|
print("Error: Number of --server and --port arguments must match")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
servers = []
|
||||||
|
for cmd, port in zip(args.servers, args.ports):
|
||||||
|
servers.append({'cmd': cmd, 'port': port})
|
||||||
|
|
||||||
|
server_processes = []
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Start all servers
|
||||||
|
for i, server in enumerate(servers):
|
||||||
|
print(f"Starting server {i+1}/{len(servers)}: {server['cmd']}")
|
||||||
|
|
||||||
|
# Use shell=True to support commands with cd and &&
|
||||||
|
process = subprocess.Popen(
|
||||||
|
server['cmd'],
|
||||||
|
shell=True,
|
||||||
|
stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.PIPE
|
||||||
|
)
|
||||||
|
server_processes.append(process)
|
||||||
|
|
||||||
|
# Wait for this server to be ready
|
||||||
|
print(f"Waiting for server on port {server['port']}...")
|
||||||
|
if not is_server_ready(server['port'], timeout=args.timeout):
|
||||||
|
raise RuntimeError(f"Server failed to start on port {server['port']} within {args.timeout}s")
|
||||||
|
|
||||||
|
print(f"Server ready on port {server['port']}")
|
||||||
|
|
||||||
|
print(f"\nAll {len(servers)} server(s) ready")
|
||||||
|
|
||||||
|
# Run the command
|
||||||
|
print(f"Running: {' '.join(args.command)}\n")
|
||||||
|
result = subprocess.run(args.command)
|
||||||
|
sys.exit(result.returncode)
|
||||||
|
|
||||||
|
finally:
|
||||||
|
# Clean up all servers
|
||||||
|
print(f"\nStopping {len(server_processes)} server(s)...")
|
||||||
|
for i, process in enumerate(server_processes):
|
||||||
|
try:
|
||||||
|
process.terminate()
|
||||||
|
process.wait(timeout=5)
|
||||||
|
except subprocess.TimeoutExpired:
|
||||||
|
process.kill()
|
||||||
|
process.wait()
|
||||||
|
print(f"Server {i+1} stopped")
|
||||||
|
print("All servers stopped")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
5236
Log/run.log
5236
Log/run.log
File diff suppressed because one or more lines are too long
160
dulizhan/library/BusinessKw/JoyHub/AddressCountryManage.py
Normal file
160
dulizhan/library/BusinessKw/JoyHub/AddressCountryManage.py
Normal file
@@ -0,0 +1,160 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
国家信息管理业务关键字层
|
||||||
|
"""
|
||||||
|
import allure
|
||||||
|
from dulizhan.library.Dlizhan_interface import DlzhanInterface
|
||||||
|
from base_framework.public_tools import log
|
||||||
|
|
||||||
|
obj_log = log.get_logger()
|
||||||
|
|
||||||
|
|
||||||
|
class AddressCountryManage(DlzhanInterface):
|
||||||
|
"""国家信息管理业务关键字类"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
@allure.step("创建国家信息")
|
||||||
|
def kw_joyhub_address_country_create_post(self, country_code, country_name, country_name_en, phone_code,
|
||||||
|
lingxing_country_code=None, paypal_country_code=None, status=1, id=0):
|
||||||
|
"""
|
||||||
|
创建国家信息业务关键字
|
||||||
|
:param id: 主键,新增为0
|
||||||
|
:param country_code: 国家代码(如 CN/US)
|
||||||
|
:param country_name: 国家名称
|
||||||
|
:param country_name_en: 国家英文名称
|
||||||
|
:param phone_code: 电话区号
|
||||||
|
:param lingxing_country_code: 领星国家代码(可选)
|
||||||
|
:param paypal_country_code: paypal国家代码(可选)
|
||||||
|
:param status: 状态 (1正常 2停用)
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"创建国家信息 - country_code: {country_code}, country_name: {country_name}, status: {status}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"id": id,
|
||||||
|
"countryCode": country_code,
|
||||||
|
"countryName": country_name,
|
||||||
|
"countryNameEn": country_name_en,
|
||||||
|
"phoneCode": phone_code,
|
||||||
|
"status": status
|
||||||
|
}
|
||||||
|
|
||||||
|
if lingxing_country_code:
|
||||||
|
params["lingxingCountryCode"] = lingxing_country_code
|
||||||
|
if paypal_country_code:
|
||||||
|
params["paypalCountryCode"] = paypal_country_code
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_address_country_create_post(**params)
|
||||||
|
obj_log.info(f"创建国家信息响应: {resp}")
|
||||||
|
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("删除国家信息")
|
||||||
|
def kw_joyhub_address_country_delete_delete(self, country_id):
|
||||||
|
"""
|
||||||
|
删除国家信息业务关键字
|
||||||
|
:param country_id: 国家信息ID
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"删除国家信息 - country_id: {country_id}")
|
||||||
|
resp = self.kw_in_joyhub_address_country_delete_delete(country_id)
|
||||||
|
obj_log.info(f"删除国家信息响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("批量删除国家信息")
|
||||||
|
def kw_joyhub_address_country_delete_list_delete(self, country_ids):
|
||||||
|
"""
|
||||||
|
批量删除国家信息业务关键字
|
||||||
|
:param country_ids: 国家信息ID列表
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"批量删除国家信息 - country_ids: {country_ids}")
|
||||||
|
resp = self.kw_in_joyhub_address_country_delete_list_delete(country_ids)
|
||||||
|
obj_log.info(f"批量删除国家信息响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得国家信息详情")
|
||||||
|
def kw_joyhub_address_country_get_get(self, country_id):
|
||||||
|
"""
|
||||||
|
获得国家信息详情业务关键字
|
||||||
|
:param country_id: 国家信息ID
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"获得国家信息详情 - country_id: {country_id}")
|
||||||
|
resp = self.kw_in_joyhub_address_country_get_get(country_id)
|
||||||
|
obj_log.info(f"获得国家信息详情响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得国家信息分页")
|
||||||
|
def kw_joyhub_address_country_page_get(self, page_num=1, page_size=10, **kwargs):
|
||||||
|
"""
|
||||||
|
获得国家信息分页业务关键字
|
||||||
|
:param page_num: 页码
|
||||||
|
:param page_size: 每页大小
|
||||||
|
:param kwargs: 其他查询条件
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"获得国家信息分页 - page_num: {page_num}, page_size: {page_size}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"page": page_num,
|
||||||
|
"size": page_size
|
||||||
|
}
|
||||||
|
params.update(kwargs)
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_address_country_page_get(**params)
|
||||||
|
obj_log.info(f"获得国家信息分页响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("更新国家信息")
|
||||||
|
def kw_joyhub_address_country_update_put(self, country_id, country_code, country_name, country_name_en, phone_code,
|
||||||
|
lingxing_country_code=None, paypal_country_code=None, status=1):
|
||||||
|
"""
|
||||||
|
更新国家信息业务关键字
|
||||||
|
:param country_id: 国家信息ID
|
||||||
|
:param country_code: 国家代码
|
||||||
|
:param country_name: 国家名称
|
||||||
|
:param country_name_en: 国家英文名称
|
||||||
|
:param phone_code: 电话区号
|
||||||
|
:param lingxing_country_code: 领星国家代码(可选)
|
||||||
|
:param paypal_country_code: paypal国家代码(可选)
|
||||||
|
:param status: 状态 (1正常 2停用)
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"更新国家信息 - country_id: {country_id}, country_code: {country_code}, country_name: {country_name}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"id": country_id,
|
||||||
|
"countryCode": country_code,
|
||||||
|
"countryName": country_name,
|
||||||
|
"countryNameEn": country_name_en,
|
||||||
|
"phoneCode": phone_code,
|
||||||
|
"status": status
|
||||||
|
}
|
||||||
|
|
||||||
|
if lingxing_country_code:
|
||||||
|
params["lingxingCountryCode"] = lingxing_country_code
|
||||||
|
if paypal_country_code:
|
||||||
|
params["paypalCountryCode"] = paypal_country_code
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_address_country_update_put(**params)
|
||||||
|
obj_log.info(f"更新国家信息响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("批量更新国家信息状态")
|
||||||
|
def kw_joyhub_address_country_update_status_list_put(self, country_ids, status):
|
||||||
|
"""
|
||||||
|
批量更新国家信息状态业务关键字
|
||||||
|
:param country_ids: 国家信息ID列表
|
||||||
|
:param status: 状态 (1正常 2停用)
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"批量更新国家信息状态 - country_ids: {country_ids}, status: {status}")
|
||||||
|
|
||||||
|
# 接口参数通过query传递,ids需要用逗号分隔
|
||||||
|
ids_str = ','.join(map(str, country_ids))
|
||||||
|
resp = self.kw_in_joyhub_address_country_update_status_list_put(ids=ids_str, status=status)
|
||||||
|
obj_log.info(f"批量更新国家信息状态响应: {resp}")
|
||||||
|
return resp
|
||||||
252
dulizhan/library/BusinessKw/JoyHub/AfterSalesPolicyManage.py
Normal file
252
dulizhan/library/BusinessKw/JoyHub/AfterSalesPolicyManage.py
Normal file
@@ -0,0 +1,252 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
current_file_path = os.path.abspath(__file__)
|
||||||
|
project_root = os.path.abspath(os.path.join(os.path.dirname(current_file_path), '../../../'))
|
||||||
|
if project_root not in sys.path:
|
||||||
|
sys.path.insert(0, project_root)
|
||||||
|
|
||||||
|
from dulizhan.library.Dlizhan_interface import DlzhanInterface
|
||||||
|
from base_framework.public_tools import log
|
||||||
|
import allure
|
||||||
|
|
||||||
|
obj_log = log.get_logger()
|
||||||
|
|
||||||
|
|
||||||
|
class AfterSalesPolicyManage(DlzhanInterface):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
# ============ 售后政策管理 ============
|
||||||
|
|
||||||
|
@allure.step("创建售后政策")
|
||||||
|
def kw_joyhub_after_sales_policy_create_post(self, title, content, lang, brand_id=0, status=1, id=0):
|
||||||
|
"""
|
||||||
|
创建售后政策业务关键字
|
||||||
|
:param id: 主键,新增为0
|
||||||
|
:param brand_id: 品牌ID
|
||||||
|
:param title: 标题
|
||||||
|
:param content: 内容
|
||||||
|
:param lang: 语言 (en 英语 de 德语 ja 日语)
|
||||||
|
:param status: 状态 (1正常 2停用)
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"创建售后政策 - title: {title}, content: {content[:50]}..., lang: {lang}, brand_id: {brand_id}, status: {status}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"id": id,
|
||||||
|
"brandId": brand_id,
|
||||||
|
"title": title,
|
||||||
|
"content": content,
|
||||||
|
"lang": lang,
|
||||||
|
"status": status
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_after_sales_policy_create_post(**params)
|
||||||
|
obj_log.info(f"创建售后政策响应: {resp}")
|
||||||
|
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("删除售后政策")
|
||||||
|
def kw_joyhub_after_sales_policy_delete_delete(self, policy_id):
|
||||||
|
"""
|
||||||
|
删除售后政策业务关键字
|
||||||
|
:param policy_id: 售后政策ID
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"删除售后政策 - policy_id: {policy_id}")
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_after_sales_policy_delete_delete(policy_id)
|
||||||
|
obj_log.info(f"删除售后政策响应: {resp}")
|
||||||
|
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("批量删除售后政策")
|
||||||
|
def kw_joyhub_after_sales_policy_delete_list_delete(self, policy_ids):
|
||||||
|
"""
|
||||||
|
批量删除售后政策业务关键字
|
||||||
|
:param policy_ids: 售后政策ID列表
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"批量删除售后政策 - policy_ids: {policy_ids}")
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_after_sales_policy_delete_list_delete(policy_ids)
|
||||||
|
obj_log.info(f"批量删除售后政策响应: {resp}")
|
||||||
|
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得售后政策详情")
|
||||||
|
def kw_joyhub_after_sales_policy_get_get(self, policy_id):
|
||||||
|
"""
|
||||||
|
获得售后政策详情业务关键字
|
||||||
|
:param policy_id: 售后政策ID
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"获得售后政策详情 - policy_id: {policy_id}")
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_after_sales_policy_get_get(policy_id)
|
||||||
|
obj_log.info(f"获得售后政策详情响应: {resp}")
|
||||||
|
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得售后政策分页列表")
|
||||||
|
def kw_joyhub_after_sales_policy_page_get(self, **kwargs):
|
||||||
|
"""
|
||||||
|
获得售后政策分页列表业务关键字
|
||||||
|
:param kwargs: 查询参数(title, content, status, page_no, page_size)
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"获得售后政策分页列表 - 参数: {kwargs}")
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_after_sales_policy_page_get(**kwargs)
|
||||||
|
obj_log.info(f"获得售后政策分页列表响应: {resp}")
|
||||||
|
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("更新售后政策")
|
||||||
|
def kw_joyhub_after_sales_policy_update_put(self, policy_id, title, content, lang, brand_id=0, status=1):
|
||||||
|
"""
|
||||||
|
更新售后政策业务关键字
|
||||||
|
:param policy_id: 售后政策ID
|
||||||
|
:param brand_id: 品牌ID
|
||||||
|
:param title: 标题
|
||||||
|
:param content: 内容
|
||||||
|
:param lang: 语言 (en 英语 de 德语 ja 日语)
|
||||||
|
:param status: 状态 (1正常 2停用)
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"更新售后政策 - policy_id: {policy_id}, title: {title}, content: {content[:50]}..., lang: {lang}, brand_id: {brand_id}, status: {status}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"id": policy_id,
|
||||||
|
"brandId": brand_id,
|
||||||
|
"title": title,
|
||||||
|
"content": content,
|
||||||
|
"lang": lang,
|
||||||
|
"status": status
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_after_sales_policy_update_put(**params)
|
||||||
|
obj_log.info(f"更新售后政策响应: {resp}")
|
||||||
|
|
||||||
|
return resp
|
||||||
|
|
||||||
|
# ============ 售后政策-品牌管理 ============
|
||||||
|
|
||||||
|
@allure.step("创建售后政策-品牌")
|
||||||
|
def kw_joyhub_after_sales_brand_create_post(self, brand_name, after_sales_policy_id, status=1, id=0):
|
||||||
|
"""
|
||||||
|
创建售后政策-品牌业务关键字
|
||||||
|
:param id: 主键,新增为0
|
||||||
|
:param brand_name: 品牌名称
|
||||||
|
:param after_sales_policy_id: 售后政策ID
|
||||||
|
:param status: 状态 (1正常 2停用)
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"创建售后政策-品牌 - brand_name: {brand_name}, after_sales_policy_id: {after_sales_policy_id}, status: {status}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"id": id,
|
||||||
|
"brandName": brand_name,
|
||||||
|
"afterSalesPolicyId": after_sales_policy_id,
|
||||||
|
"status": status
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_after_sales_brand_create_post(**params)
|
||||||
|
obj_log.info(f"创建售后政策-品牌响应: {resp}")
|
||||||
|
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("删除售后政策-品牌")
|
||||||
|
def kw_joyhub_after_sales_brand_delete_delete(self, brand_id):
|
||||||
|
"""
|
||||||
|
删除售后政策-品牌业务关键字
|
||||||
|
:param brand_id: 售后政策-品牌ID
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"删除售后政策-品牌 - brand_id: {brand_id}")
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_after_sales_brand_delete_delete(brand_id)
|
||||||
|
obj_log.info(f"删除售后政策-品牌响应: {resp}")
|
||||||
|
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("批量删除售后政策-品牌")
|
||||||
|
def kw_joyhub_after_sales_brand_delete_list_delete(self, brand_ids):
|
||||||
|
"""
|
||||||
|
批量删除售后政策-品牌业务关键字
|
||||||
|
:param brand_ids: 售后政策-品牌ID列表
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"批量删除售后政策-品牌 - brand_ids: {brand_ids}")
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_after_sales_brand_delete_list_delete(brand_ids)
|
||||||
|
obj_log.info(f"批量删除售后政策-品牌响应: {resp}")
|
||||||
|
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得售后政策-品牌详情")
|
||||||
|
def kw_joyhub_after_sales_brand_get_get(self, brand_id):
|
||||||
|
"""
|
||||||
|
获得售后政策-品牌详情业务关键字
|
||||||
|
:param brand_id: 售后政策-品牌ID
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"获得售后政策-品牌详情 - brand_id: {brand_id}")
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_after_sales_brand_get_get(brand_id)
|
||||||
|
obj_log.info(f"获得售后政策-品牌详情响应: {resp}")
|
||||||
|
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得可用的品牌列表")
|
||||||
|
def kw_joyhub_after_sales_brand_list_available_get(self):
|
||||||
|
"""
|
||||||
|
获得可用的品牌列表业务关键字
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info("获得可用的品牌列表")
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_after_sales_brand_list_available_get()
|
||||||
|
obj_log.info(f"获得可用的品牌列表响应: {resp}")
|
||||||
|
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得售后政策-品牌分页列表")
|
||||||
|
def kw_joyhub_after_sales_brand_page_get(self, **kwargs):
|
||||||
|
"""
|
||||||
|
获得售后政策-品牌分页列表业务关键字
|
||||||
|
:param kwargs: 查询参数(brand_name, after_sales_policy_id, status, page_no, page_size)
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"获得售后政策-品牌分页列表 - 参数: {kwargs}")
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_after_sales_brand_page_get(**kwargs)
|
||||||
|
obj_log.info(f"获得售后政策-品牌分页列表响应: {resp}")
|
||||||
|
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("更新售后政策-品牌")
|
||||||
|
def kw_joyhub_after_sales_brand_update_put(self, brand_id, brand_name, after_sales_policy_id, status=1):
|
||||||
|
"""
|
||||||
|
更新售后政策-品牌业务关键字
|
||||||
|
:param brand_id: 售后政策-品牌ID
|
||||||
|
:param brand_name: 品牌名称
|
||||||
|
:param after_sales_policy_id: 售后政策ID
|
||||||
|
:param status: 状态 (1正常 2停用)
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"更新售后政策-品牌 - brand_id: {brand_id}, brand_name: {brand_name}, after_sales_policy_id: {after_sales_policy_id}, status: {status}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"id": brand_id,
|
||||||
|
"brandName": brand_name,
|
||||||
|
"afterSalesPolicyId": after_sales_policy_id,
|
||||||
|
"status": status
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_after_sales_brand_update_put(**params)
|
||||||
|
obj_log.info(f"更新售后政策-品牌响应: {resp}")
|
||||||
|
|
||||||
|
return resp
|
||||||
130
dulizhan/library/BusinessKw/JoyHub/BlogCateManage.py
Normal file
130
dulizhan/library/BusinessKw/JoyHub/BlogCateManage.py
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
blog分类管理业务关键字层
|
||||||
|
"""
|
||||||
|
import allure
|
||||||
|
from dulizhan.library.Dlizhan_interface import DlzhanInterface
|
||||||
|
from base_framework.public_tools import log
|
||||||
|
|
||||||
|
obj_log = log.get_logger()
|
||||||
|
|
||||||
|
|
||||||
|
class BlogCateManage(DlzhanInterface):
|
||||||
|
"""blog分类管理业务关键字类"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
@allure.step("创建blog分类")
|
||||||
|
def kw_joyhub_blog_cate_create_post(self, name, id=0, status=1, rank_num=None, route=None, cover_image=None):
|
||||||
|
"""
|
||||||
|
创建blog分类业务关键字
|
||||||
|
:param id: 主键,新增为0
|
||||||
|
:param name: 分类名称
|
||||||
|
:param status: 状态 (1正常 2停用)
|
||||||
|
:param rank_num: 排序(可选)
|
||||||
|
:param route: 路由(可选)
|
||||||
|
:param cover_image: 封面图对象,格式: {"url": "xxx", "name": None, "alt": ""}(可选)
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"创建blog分类 - name: {name}, status: {status}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"id": id,
|
||||||
|
"name": name,
|
||||||
|
"status": status
|
||||||
|
}
|
||||||
|
|
||||||
|
if rank_num is not None:
|
||||||
|
params["rankNum"] = rank_num
|
||||||
|
if route is not None:
|
||||||
|
params["route"] = route
|
||||||
|
if cover_image is not None:
|
||||||
|
if isinstance(cover_image, str):
|
||||||
|
params["coverImage"] = {"url": cover_image, "name": None, "alt": ""}
|
||||||
|
else:
|
||||||
|
params["coverImage"] = cover_image
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_blog_cate_create_post(**params)
|
||||||
|
obj_log.info(f"创建blog分类响应: {resp}")
|
||||||
|
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("删除blog分类")
|
||||||
|
def kw_joyhub_blog_cate_delete_delete(self, cate_id):
|
||||||
|
"""
|
||||||
|
删除blog分类业务关键字
|
||||||
|
:param cate_id: blog分类ID
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"删除blog分类 - cate_id: {cate_id}")
|
||||||
|
resp = self.kw_in_joyhub_blog_cate_delete_delete(cate_id)
|
||||||
|
obj_log.info(f"删除blog分类响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得blog分类详情")
|
||||||
|
def kw_joyhub_blog_cate_get_get(self, cate_id):
|
||||||
|
"""
|
||||||
|
获得blog分类详情业务关键字
|
||||||
|
:param cate_id: blog分类ID
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"获得blog分类详情 - cate_id: {cate_id}")
|
||||||
|
resp = self.kw_in_joyhub_blog_cate_get_get(cate_id)
|
||||||
|
obj_log.info(f"获得blog分类详情响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得blog分类分页")
|
||||||
|
def kw_joyhub_blog_cate_page_get(self, page_num=1, page_size=10, **kwargs):
|
||||||
|
"""
|
||||||
|
获得blog分类分页业务关键字
|
||||||
|
:param page_num: 页码
|
||||||
|
:param page_size: 每页大小
|
||||||
|
:param kwargs: 其他查询条件
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"获得blog分类分页 - page_num: {page_num}, page_size: {page_size}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"page": page_num,
|
||||||
|
"size": page_size
|
||||||
|
}
|
||||||
|
params.update(kwargs)
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_blog_cate_page_get(**params)
|
||||||
|
obj_log.info(f"获得blog分类分页响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("更新blog分类")
|
||||||
|
def kw_joyhub_blog_cate_update_put(self, cate_id, name, status=1, rank_num=None, route=None, cover_image=None):
|
||||||
|
"""
|
||||||
|
更新blog分类业务关键字
|
||||||
|
:param cate_id: blog分类ID
|
||||||
|
:param name: 分类名称
|
||||||
|
:param status: 状态 (1正常 2停用)
|
||||||
|
:param rank_num: 排序(可选)
|
||||||
|
:param route: 路由(可选)
|
||||||
|
:param cover_image: 封面图对象,格式: {"url": "xxx", "name": None, "alt": ""}(可选)
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"更新blog分类 - cate_id: {cate_id}, name: {name}, status: {status}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"id": cate_id,
|
||||||
|
"name": name,
|
||||||
|
"status": status
|
||||||
|
}
|
||||||
|
|
||||||
|
if rank_num is not None:
|
||||||
|
params["rankNum"] = rank_num
|
||||||
|
if route is not None:
|
||||||
|
params["route"] = route
|
||||||
|
if cover_image is not None:
|
||||||
|
if isinstance(cover_image, str):
|
||||||
|
params["coverImage"] = {"url": cover_image, "name": None, "alt": ""}
|
||||||
|
else:
|
||||||
|
params["coverImage"] = cover_image
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_blog_cate_update_put(**params)
|
||||||
|
obj_log.info(f"更新blog分类响应: {resp}")
|
||||||
|
return resp
|
||||||
125
dulizhan/library/BusinessKw/JoyHub/DownloadQrcodeManage.py
Normal file
125
dulizhan/library/BusinessKw/JoyHub/DownloadQrcodeManage.py
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
二维码管理业务关键字层
|
||||||
|
"""
|
||||||
|
import allure
|
||||||
|
from dulizhan.library.Dlizhan_interface import DlzhanInterface
|
||||||
|
from base_framework.public_tools import log
|
||||||
|
|
||||||
|
obj_log = log.get_logger()
|
||||||
|
|
||||||
|
|
||||||
|
class DownloadQrcodeManage(DlzhanInterface):
|
||||||
|
"""二维码管理业务关键字类"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
@allure.step("创建二维码")
|
||||||
|
def kw_joyhub_download_qrcode_create_post(self, title, id=0, status=1):
|
||||||
|
"""
|
||||||
|
创建二维码业务关键字
|
||||||
|
:param id: 主键,新增为0
|
||||||
|
:param title: 标题
|
||||||
|
:param status: 状态 (1正常 2停用)
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"创建二维码 - title: {title}, status: {status}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"id": id,
|
||||||
|
"title": title,
|
||||||
|
"status": status
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_download_qrcode_create_post(**params)
|
||||||
|
obj_log.info(f"创建二维码响应: {resp}")
|
||||||
|
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得二维码详情")
|
||||||
|
def kw_joyhub_download_qrcode_get_get(self, qrcode_id):
|
||||||
|
"""
|
||||||
|
获得二维码详情业务关键字
|
||||||
|
:param qrcode_id: 二维码ID
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"获得二维码详情 - qrcode_id: {qrcode_id}")
|
||||||
|
resp = self.kw_in_joyhub_download_qrcode_get_get(qrcode_id)
|
||||||
|
obj_log.info(f"获得二维码详情响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得二维码分页")
|
||||||
|
def kw_joyhub_download_qrcode_page_get(self, page_no=1, page_size=10, **kwargs):
|
||||||
|
"""
|
||||||
|
获得二维码分页业务关键字
|
||||||
|
:param page_no: 页码
|
||||||
|
:param page_size: 每页大小
|
||||||
|
:param kwargs: 其他查询条件
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"获得二维码分页 - page_no: {page_no}, page_size: {page_size}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"pageNo": page_no,
|
||||||
|
"pageSize": page_size
|
||||||
|
}
|
||||||
|
params.update(kwargs)
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_download_qrcode_page_get(**params)
|
||||||
|
obj_log.info(f"获得二维码分页响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("更新二维码")
|
||||||
|
def kw_joyhub_download_qrcode_update_put(self, qrcode_id, title, status=1):
|
||||||
|
"""
|
||||||
|
更新二维码业务关键字
|
||||||
|
:param qrcode_id: 二维码ID
|
||||||
|
:param title: 标题
|
||||||
|
:param status: 状态 (1正常 2停用)
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"更新二维码 - qrcode_id: {qrcode_id}, title: {title}, status: {status}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"id": qrcode_id,
|
||||||
|
"title": title,
|
||||||
|
"status": status
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_download_qrcode_update_put(**params)
|
||||||
|
obj_log.info(f"更新二维码响应: {resp}")
|
||||||
|
|
||||||
|
return resp
|
||||||
|
|
||||||
|
def clean_test_data_from_db(self, title):
|
||||||
|
"""
|
||||||
|
从数据库表jh_download_qrcode中删除测试数据
|
||||||
|
:param title: 要删除的二维码标题
|
||||||
|
:return: 删除是否成功
|
||||||
|
"""
|
||||||
|
obj_log.info(f"从数据库删除测试数据 - title: {title}")
|
||||||
|
try:
|
||||||
|
import pymysql
|
||||||
|
# 数据库连接配置(需要根据实际环境配置)
|
||||||
|
connection = pymysql.connect(
|
||||||
|
host='localhost',
|
||||||
|
user='root',
|
||||||
|
password='password',
|
||||||
|
database='joyhub',
|
||||||
|
charset='utf8mb4'
|
||||||
|
)
|
||||||
|
|
||||||
|
with connection.cursor() as cursor:
|
||||||
|
sql = "DELETE FROM jh_download_qrcode WHERE title LIKE %s"
|
||||||
|
cursor.execute(sql, (f"%{title}%",))
|
||||||
|
connection.commit()
|
||||||
|
deleted_count = cursor.rowcount
|
||||||
|
obj_log.info(f"成功删除 {deleted_count} 条测试数据")
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
obj_log.error(f"删除测试数据失败: {str(e)}")
|
||||||
|
return False
|
||||||
|
finally:
|
||||||
|
if 'connection' in locals():
|
||||||
|
connection.close()
|
||||||
108
dulizhan/library/BusinessKw/JoyHub/FaqCateManage.py
Normal file
108
dulizhan/library/BusinessKw/JoyHub/FaqCateManage.py
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
FAQ分类管理业务关键字层
|
||||||
|
"""
|
||||||
|
import allure
|
||||||
|
from dulizhan.library.Dlizhan_interface import DlzhanInterface
|
||||||
|
from base_framework.public_tools import log
|
||||||
|
|
||||||
|
obj_log = log.get_logger()
|
||||||
|
|
||||||
|
|
||||||
|
class FaqCateManage(DlzhanInterface):
|
||||||
|
"""FAQ分类管理业务关键字类"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
@allure.step("创建FAQ分类")
|
||||||
|
def kw_joyhub_faq_cate_create_post(self, title, lang, rank_num, pid=0, status=1, id=0):
|
||||||
|
"""
|
||||||
|
创建FAQ分类业务关键字
|
||||||
|
:param id: 主键,新增为0
|
||||||
|
:param pid: 父分类ID,默认为0(顶级分类)
|
||||||
|
:param title: 分类名称
|
||||||
|
:param status: 状态 (1正常 2停用)
|
||||||
|
:param rank_num: 排序号
|
||||||
|
:param lang: 语言 (en 英语 de 德语 ja 日语)
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"创建FAQ分类 - title: {title}, lang: {lang}, pid: {pid}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"id": id,
|
||||||
|
"pid": pid,
|
||||||
|
"title": title,
|
||||||
|
"status": status,
|
||||||
|
"rankNum": rank_num,
|
||||||
|
"lang": lang
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_faq_cate_create_post(**params)
|
||||||
|
obj_log.info(f"创建FAQ分类响应: {resp}")
|
||||||
|
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("删除FAQ分类")
|
||||||
|
def kw_joyhub_faq_cate_delete_delete(self, faq_cate_id):
|
||||||
|
"""
|
||||||
|
删除FAQ分类业务关键字
|
||||||
|
:param faq_cate_id: FAQ分类ID
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"删除FAQ分类 - faq_cate_id: {faq_cate_id}")
|
||||||
|
resp = self.kw_in_joyhub_faq_cate_delete_delete(faq_cate_id)
|
||||||
|
obj_log.info(f"删除FAQ分类响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得FAQ分类详情")
|
||||||
|
def kw_joyhub_faq_cate_get_get(self, faq_cate_id):
|
||||||
|
"""
|
||||||
|
获得FAQ分类详情业务关键字
|
||||||
|
:param faq_cate_id: FAQ分类ID
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"获得FAQ分类详情 - faq_cate_id: {faq_cate_id}")
|
||||||
|
resp = self.kw_in_joyhub_faq_cate_get_get(faq_cate_id)
|
||||||
|
obj_log.info(f"获得FAQ分类详情响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得FAQ分类列表")
|
||||||
|
def kw_joyhub_faq_cate_list_get(self, **kwargs):
|
||||||
|
"""
|
||||||
|
获得FAQ分类列表业务关键字
|
||||||
|
:param kwargs: 其他查询条件
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"获得FAQ分类列表 - kwargs: {kwargs}")
|
||||||
|
resp = self.kw_in_joyhub_faq_cate_list_get(**kwargs)
|
||||||
|
obj_log.info(f"获得FAQ分类列表响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("更新FAQ分类")
|
||||||
|
def kw_joyhub_faq_cate_update_put(self, faq_cate_id, title, lang, rank_num, pid=0, status=1):
|
||||||
|
"""
|
||||||
|
更新FAQ分类业务关键字
|
||||||
|
:param faq_cate_id: FAQ分类ID
|
||||||
|
:param pid: 父分类ID
|
||||||
|
:param title: 分类名称
|
||||||
|
:param status: 状态 (1正常 2停用)
|
||||||
|
:param rank_num: 排序号
|
||||||
|
:param lang: 语言 (en 英语 de 德语 ja 日语)
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"更新FAQ分类 - faq_cate_id: {faq_cate_id}, title: {title}, lang: {lang}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"id": faq_cate_id,
|
||||||
|
"pid": pid,
|
||||||
|
"title": title,
|
||||||
|
"status": status,
|
||||||
|
"rankNum": rank_num,
|
||||||
|
"lang": lang
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_faq_cate_update_put(**params)
|
||||||
|
obj_log.info(f"更新FAQ分类响应: {resp}")
|
||||||
|
|
||||||
|
return resp
|
||||||
148
dulizhan/library/BusinessKw/JoyHub/FaqManage.py
Normal file
148
dulizhan/library/BusinessKw/JoyHub/FaqManage.py
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
FAQ数据管理业务关键字层
|
||||||
|
"""
|
||||||
|
import allure
|
||||||
|
from dulizhan.library.Dlizhan_interface import DlzhanInterface
|
||||||
|
from base_framework.public_tools import log
|
||||||
|
|
||||||
|
obj_log = log.get_logger()
|
||||||
|
|
||||||
|
|
||||||
|
class FaqManage(DlzhanInterface):
|
||||||
|
"""FAQ数据管理业务关键字类"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
@allure.step("获得FAQ分类下拉列表")
|
||||||
|
def kw_joyhub_faq_cate_list_get(self):
|
||||||
|
"""
|
||||||
|
获得FAQ分类下拉列表业务关键字
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info("获得FAQ分类下拉列表")
|
||||||
|
resp = self.kw_in_joyhub_faq_cate_list_get()
|
||||||
|
obj_log.info(f"获得FAQ分类下拉列表响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("创建FAQ数据")
|
||||||
|
def kw_joyhub_faq_create_post(self, faq_cate_id, question, answer, rank_num, lang, is_hot=0, status=1, id=0):
|
||||||
|
"""
|
||||||
|
创建FAQ数据业务关键字
|
||||||
|
:param id: 主键,新增为0
|
||||||
|
:param faq_cate_id: 分类ID
|
||||||
|
:param question: 常见问题
|
||||||
|
:param answer: 回答
|
||||||
|
:param is_hot: 是否热门(0否,1是)
|
||||||
|
:param status: 状态 (1正常 2停用)
|
||||||
|
:param rank_num: 排序号
|
||||||
|
:param lang: 语言 (en 英语 de 德语 ja 日语)
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"创建FAQ数据 - question: {question}, lang: {lang}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"id": id,
|
||||||
|
"faqCateId": faq_cate_id,
|
||||||
|
"question": question,
|
||||||
|
"answer": answer,
|
||||||
|
"isHot": is_hot,
|
||||||
|
"status": status,
|
||||||
|
"rankNum": rank_num,
|
||||||
|
"lang": lang
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_faq_create_post(**params)
|
||||||
|
obj_log.info(f"创建FAQ数据响应: {resp}")
|
||||||
|
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("删除FAQ数据")
|
||||||
|
def kw_joyhub_faq_delete_delete(self, faq_id):
|
||||||
|
"""
|
||||||
|
删除FAQ数据业务关键字
|
||||||
|
:param faq_id: FAQ数据ID
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"删除FAQ数据 - faq_id: {faq_id}")
|
||||||
|
resp = self.kw_in_joyhub_faq_delete_delete(faq_id)
|
||||||
|
obj_log.info(f"删除FAQ数据响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("批量删除FAQ数据")
|
||||||
|
def kw_joyhub_faq_delete_list_delete(self, ids):
|
||||||
|
"""
|
||||||
|
批量删除FAQ数据业务关键字
|
||||||
|
:param ids: FAQ数据ID列表
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"批量删除FAQ数据 - ids: {ids}")
|
||||||
|
resp = self.kw_in_joyhub_faq_delete_list_delete(ids)
|
||||||
|
obj_log.info(f"批量删除FAQ数据响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得FAQ数据详情")
|
||||||
|
def kw_joyhub_faq_get_get(self, faq_id):
|
||||||
|
"""
|
||||||
|
获得FAQ数据详情业务关键字
|
||||||
|
:param faq_id: FAQ数据ID
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"获得FAQ数据详情 - faq_id: {faq_id}")
|
||||||
|
resp = self.kw_in_joyhub_faq_get_get(faq_id)
|
||||||
|
obj_log.info(f"获得FAQ数据详情响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得FAQ数据分页")
|
||||||
|
def kw_joyhub_faq_page_get(self, page_no=1, page_size=10, **kwargs):
|
||||||
|
"""
|
||||||
|
获得FAQ数据分页业务关键字
|
||||||
|
:param page_no: 页码
|
||||||
|
:param page_size: 每页大小
|
||||||
|
:param kwargs: 其他查询条件
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"获得FAQ数据分页 - page_no: {page_no}, page_size: {page_size}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"pageNo": page_no,
|
||||||
|
"pageSize": page_size
|
||||||
|
}
|
||||||
|
params.update(kwargs)
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_faq_page_get(**params)
|
||||||
|
obj_log.info(f"获得FAQ数据分页响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("更新FAQ数据")
|
||||||
|
def kw_joyhub_faq_update_put(self, faq_id, faq_cate_id, question, answer, rank_num, lang, is_hot=0, status=1):
|
||||||
|
"""
|
||||||
|
更新FAQ数据业务关键字
|
||||||
|
:param faq_id: FAQ数据ID
|
||||||
|
:param faq_cate_id: 分类ID
|
||||||
|
:param question: 常见问题
|
||||||
|
:param answer: 回答
|
||||||
|
:param is_hot: 是否热门(0否,1是)
|
||||||
|
:param status: 状态 (1正常 2停用)
|
||||||
|
:param rank_num: 排序号
|
||||||
|
:param lang: 语言 (en 英语 de 德语 ja 日语)
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"更新FAQ数据 - faq_id: {faq_id}, question: {question}, lang: {lang}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"id": faq_id,
|
||||||
|
"faqCateId": faq_cate_id,
|
||||||
|
"question": question,
|
||||||
|
"answer": answer,
|
||||||
|
"isHot": is_hot,
|
||||||
|
"status": status,
|
||||||
|
"rankNum": rank_num,
|
||||||
|
"lang": lang
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_faq_update_put(**params)
|
||||||
|
obj_log.info(f"更新FAQ数据响应: {resp}")
|
||||||
|
|
||||||
|
return resp
|
||||||
167
dulizhan/library/BusinessKw/JoyHub/NewsCateManage.py
Normal file
167
dulizhan/library/BusinessKw/JoyHub/NewsCateManage.py
Normal file
@@ -0,0 +1,167 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
news分类管理业务关键字层
|
||||||
|
"""
|
||||||
|
import allure
|
||||||
|
from dulizhan.library.Dlizhan_interface import DlzhanInterface
|
||||||
|
from base_framework.public_tools import log
|
||||||
|
|
||||||
|
obj_log = log.get_logger()
|
||||||
|
|
||||||
|
|
||||||
|
class NewsCateManage(DlzhanInterface):
|
||||||
|
"""news分类管理业务关键字类"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
@allure.step("创建news分类")
|
||||||
|
def kw_joyhub_news_cate_create_post(self, name, id=0, status=1, rank_num=1, route=None, cover_image=None):
|
||||||
|
"""
|
||||||
|
创建news分类业务关键字
|
||||||
|
:param id: 主键,新增为0
|
||||||
|
:param name: 分类名称
|
||||||
|
:param status: 状态 (1正常 2停用)
|
||||||
|
:param rank_num: 排序号
|
||||||
|
:param route: 路由(可选)
|
||||||
|
:param cover_image: 缩略图(可选)
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"创建news分类 - name: {name}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"id": id,
|
||||||
|
"name": name,
|
||||||
|
"status": status,
|
||||||
|
"rankNum": rank_num
|
||||||
|
}
|
||||||
|
|
||||||
|
if route is not None:
|
||||||
|
params["route"] = route
|
||||||
|
if cover_image is not None:
|
||||||
|
params["coverImage"] = cover_image
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_news_cate_create_post(**params)
|
||||||
|
obj_log.info(f"创建news分类响应: {resp}")
|
||||||
|
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("删除news分类")
|
||||||
|
def kw_joyhub_news_cate_delete_delete(self, news_cate_id):
|
||||||
|
"""
|
||||||
|
删除news分类业务关键字
|
||||||
|
:param news_cate_id: news分类ID
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"删除news分类 - news_cate_id: {news_cate_id}")
|
||||||
|
resp = self.kw_in_joyhub_news_cate_delete_delete(news_cate_id)
|
||||||
|
obj_log.info(f"删除news分类响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("批量删除news分类")
|
||||||
|
def kw_joyhub_news_cate_delete_list_delete(self, ids):
|
||||||
|
"""
|
||||||
|
批量删除news分类业务关键字
|
||||||
|
:param ids: news分类ID列表
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"批量删除news分类 - ids: {ids}")
|
||||||
|
resp = self.kw_in_joyhub_news_cate_delete_list_delete(ids)
|
||||||
|
obj_log.info(f"批量删除news分类响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得news分类详情")
|
||||||
|
def kw_joyhub_news_cate_get_get(self, news_cate_id):
|
||||||
|
"""
|
||||||
|
获得news分类详情业务关键字
|
||||||
|
:param news_cate_id: news分类ID
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"获得news分类详情 - news_cate_id: {news_cate_id}")
|
||||||
|
resp = self.kw_in_joyhub_news_cate_get_get(news_cate_id)
|
||||||
|
obj_log.info(f"获得news分类详情响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得news分类分页")
|
||||||
|
def kw_joyhub_news_cate_page_get(self, page_no=1, page_size=10, **kwargs):
|
||||||
|
"""
|
||||||
|
获得news分类分页业务关键字
|
||||||
|
:param page_no: 页码
|
||||||
|
:param page_size: 每页大小
|
||||||
|
:param kwargs: 其他查询条件
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"获得news分类分页 - page_no: {page_no}, page_size: {page_size}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"pageNo": page_no,
|
||||||
|
"pageSize": page_size
|
||||||
|
}
|
||||||
|
params.update(kwargs)
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_news_cate_page_get(**params)
|
||||||
|
obj_log.info(f"获得news分类分页响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("更新news分类")
|
||||||
|
def kw_joyhub_news_cate_update_put(self, news_cate_id, name, status=1, rank_num=1, route=None, cover_image=None):
|
||||||
|
"""
|
||||||
|
更新news分类业务关键字
|
||||||
|
:param news_cate_id: news分类ID
|
||||||
|
:param name: 分类名称
|
||||||
|
:param status: 状态 (1正常 2停用)
|
||||||
|
:param rank_num: 排序号
|
||||||
|
:param route: 路由(可选)
|
||||||
|
:param cover_image: 缩略图(可选)
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"更新news分类 - news_cate_id: {news_cate_id}, name: {name}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"id": news_cate_id,
|
||||||
|
"name": name,
|
||||||
|
"status": status,
|
||||||
|
"rankNum": rank_num
|
||||||
|
}
|
||||||
|
|
||||||
|
if route is not None:
|
||||||
|
params["route"] = route
|
||||||
|
if cover_image is not None:
|
||||||
|
params["coverImage"] = cover_image
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_news_cate_update_put(**params)
|
||||||
|
obj_log.info(f"更新news分类响应: {resp}")
|
||||||
|
|
||||||
|
return resp
|
||||||
|
|
||||||
|
def clean_test_data_from_db(self, name):
|
||||||
|
"""
|
||||||
|
从数据库表jh_news_cate中删除测试数据
|
||||||
|
:param name: 要删除的分类名称
|
||||||
|
:return: 删除是否成功
|
||||||
|
"""
|
||||||
|
obj_log.info(f"从数据库删除测试数据 - name: {name}")
|
||||||
|
try:
|
||||||
|
import pymysql
|
||||||
|
# 数据库连接配置(需要根据实际环境配置)
|
||||||
|
connection = pymysql.connect(
|
||||||
|
host='localhost',
|
||||||
|
user='root',
|
||||||
|
password='password',
|
||||||
|
database='joyhub',
|
||||||
|
charset='utf8mb4'
|
||||||
|
)
|
||||||
|
|
||||||
|
with connection.cursor() as cursor:
|
||||||
|
sql = "DELETE FROM jh_news_cate WHERE name LIKE %s"
|
||||||
|
cursor.execute(sql, (f"%{name}%",))
|
||||||
|
connection.commit()
|
||||||
|
deleted_count = cursor.rowcount
|
||||||
|
obj_log.info(f"成功删除 {deleted_count} 条测试数据")
|
||||||
|
return True
|
||||||
|
except Exception as e:
|
||||||
|
obj_log.error(f"删除测试数据失败: {str(e)}")
|
||||||
|
return False
|
||||||
|
finally:
|
||||||
|
if 'connection' in locals():
|
||||||
|
connection.close()
|
||||||
187
dulizhan/library/BusinessKw/JoyHub/NewsManage.py
Normal file
187
dulizhan/library/BusinessKw/JoyHub/NewsManage.py
Normal file
@@ -0,0 +1,187 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
news管理业务关键字层
|
||||||
|
"""
|
||||||
|
import allure
|
||||||
|
from dulizhan.library.Dlizhan_interface import DlzhanInterface
|
||||||
|
from base_framework.public_tools import log
|
||||||
|
|
||||||
|
obj_log = log.get_logger()
|
||||||
|
|
||||||
|
|
||||||
|
class NewsManage(DlzhanInterface):
|
||||||
|
"""news管理业务关键字类"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
@allure.step("创建news管理")
|
||||||
|
def kw_joyhub_news_create_post(self, title, cover_image, content, id=0, status=1, rank_num=1,
|
||||||
|
seo_title=None, seo_keyword=None, seo_description=None,
|
||||||
|
likes_num=0, cate_ids=None, route=None, publish_time=None):
|
||||||
|
"""
|
||||||
|
创建news管理业务关键字
|
||||||
|
:param id: 主键,新增为0
|
||||||
|
:param title: 标题
|
||||||
|
:param cover_image: 缩略图
|
||||||
|
:param content: PC页面内容
|
||||||
|
:param status: 状态 (1正常 2停用)
|
||||||
|
:param rank_num: 排序号
|
||||||
|
:param seo_title: SEO标题(可选)
|
||||||
|
:param seo_keyword: SEO关键词(可选)
|
||||||
|
:param seo_description: SEO描述(可选)
|
||||||
|
:param likes_num: 点赞数(可选)
|
||||||
|
:param cate_ids: news分类ID列表(可选)
|
||||||
|
:param route: 路由(可选)
|
||||||
|
:param publish_time: 发布时间(可选)
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"创建news管理 - title: {title}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"id": id,
|
||||||
|
"title": title,
|
||||||
|
"coverImage": cover_image,
|
||||||
|
"content": content,
|
||||||
|
"status": status,
|
||||||
|
"rankNum": rank_num,
|
||||||
|
"likesNum": likes_num
|
||||||
|
}
|
||||||
|
|
||||||
|
if seo_title is not None:
|
||||||
|
params["seoTitle"] = seo_title
|
||||||
|
if seo_keyword is not None:
|
||||||
|
params["seoKeyword"] = seo_keyword
|
||||||
|
if seo_description is not None:
|
||||||
|
params["seoDescription"] = seo_description
|
||||||
|
if cate_ids is not None:
|
||||||
|
params["cateIds"] = cate_ids
|
||||||
|
if route is not None:
|
||||||
|
params["route"] = route
|
||||||
|
if publish_time is not None:
|
||||||
|
params["publishTime"] = publish_time
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_news_create_post(**params)
|
||||||
|
obj_log.info(f"创建news管理响应: {resp}")
|
||||||
|
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("删除news管理")
|
||||||
|
def kw_joyhub_news_delete_delete(self, news_id):
|
||||||
|
"""
|
||||||
|
删除news管理业务关键字
|
||||||
|
:param news_id: news管理ID
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"删除news管理 - news_id: {news_id}")
|
||||||
|
resp = self.kw_in_joyhub_news_delete_delete(news_id)
|
||||||
|
obj_log.info(f"删除news管理响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("批量删除news管理")
|
||||||
|
def kw_joyhub_news_delete_list_delete(self, ids):
|
||||||
|
"""
|
||||||
|
批量删除news管理业务关键字
|
||||||
|
:param ids: news管理ID列表
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"批量删除news管理 - ids: {ids}")
|
||||||
|
resp = self.kw_in_joyhub_news_delete_list_delete(ids)
|
||||||
|
obj_log.info(f"批量删除news管理响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得news管理详情")
|
||||||
|
def kw_joyhub_news_get_get(self, news_id):
|
||||||
|
"""
|
||||||
|
获得news管理详情业务关键字
|
||||||
|
:param news_id: news管理ID
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"获得news管理详情 - news_id: {news_id}")
|
||||||
|
resp = self.kw_in_joyhub_news_get_get(news_id)
|
||||||
|
obj_log.info(f"获得news管理详情响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得news分类关联列表")
|
||||||
|
def kw_joyhub_news_cate_relation_list_get(self, news_id):
|
||||||
|
"""
|
||||||
|
获得news分类关联列表业务关键字
|
||||||
|
:param news_id: news管理ID
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"获得news分类关联列表 - news_id: {news_id}")
|
||||||
|
resp = self.kw_in_joyhub_news_cate_relation_list_get(news_id)
|
||||||
|
obj_log.info(f"获得news分类关联列表响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得news管理分页")
|
||||||
|
def kw_joyhub_news_page_get(self, page_no=1, page_size=10, **kwargs):
|
||||||
|
"""
|
||||||
|
获得news管理分页业务关键字
|
||||||
|
:param page_no: 页码
|
||||||
|
:param page_size: 每页大小
|
||||||
|
:param kwargs: 其他查询条件
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"获得news管理分页 - page_no: {page_no}, page_size: {page_size}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"pageNo": page_no,
|
||||||
|
"pageSize": page_size
|
||||||
|
}
|
||||||
|
params.update(kwargs)
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_news_page_get(**params)
|
||||||
|
obj_log.info(f"获得news管理分页响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("更新news管理")
|
||||||
|
def kw_joyhub_news_update_put(self, news_id, title, cover_image, content, status=1, rank_num=1,
|
||||||
|
seo_title=None, seo_keyword=None, seo_description=None,
|
||||||
|
likes_num=0, cate_ids=None, route=None, publish_time=None):
|
||||||
|
"""
|
||||||
|
更新news管理业务关键字
|
||||||
|
:param news_id: news管理ID
|
||||||
|
:param title: 标题
|
||||||
|
:param cover_image: 缩略图
|
||||||
|
:param content: PC页面内容
|
||||||
|
:param status: 状态 (1正常 2停用)
|
||||||
|
:param rank_num: 排序号
|
||||||
|
:param seo_title: SEO标题(可选)
|
||||||
|
:param seo_keyword: SEO关键词(可选)
|
||||||
|
:param seo_description: SEO描述(可选)
|
||||||
|
:param likes_num: 点赞数(可选)
|
||||||
|
:param cate_ids: news分类ID列表(可选)
|
||||||
|
:param route: 路由(可选)
|
||||||
|
:param publish_time: 发布时间(可选)
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"更新news管理 - news_id: {news_id}, title: {title}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"id": news_id,
|
||||||
|
"title": title,
|
||||||
|
"coverImage": cover_image,
|
||||||
|
"content": content,
|
||||||
|
"status": status,
|
||||||
|
"rankNum": rank_num,
|
||||||
|
"likesNum": likes_num
|
||||||
|
}
|
||||||
|
|
||||||
|
if seo_title is not None:
|
||||||
|
params["seoTitle"] = seo_title
|
||||||
|
if seo_keyword is not None:
|
||||||
|
params["seoKeyword"] = seo_keyword
|
||||||
|
if seo_description is not None:
|
||||||
|
params["seoDescription"] = seo_description
|
||||||
|
if cate_ids is not None:
|
||||||
|
params["cateIds"] = cate_ids
|
||||||
|
if route is not None:
|
||||||
|
params["route"] = route
|
||||||
|
if publish_time is not None:
|
||||||
|
params["publishTime"] = publish_time
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_news_update_put(**params)
|
||||||
|
obj_log.info(f"更新news管理响应: {resp}")
|
||||||
|
|
||||||
|
return resp
|
||||||
268
dulizhan/library/BusinessKw/JoyHub/ProductAttrManage.py
Normal file
268
dulizhan/library/BusinessKw/JoyHub/ProductAttrManage.py
Normal file
@@ -0,0 +1,268 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
产品属性+产品属性值管理业务关键字层
|
||||||
|
"""
|
||||||
|
import allure
|
||||||
|
from dulizhan.library.Dlizhan_interface import DlzhanInterface
|
||||||
|
from base_framework.public_tools import log
|
||||||
|
|
||||||
|
obj_log = log.get_logger()
|
||||||
|
|
||||||
|
|
||||||
|
class ProductAttrManage(DlzhanInterface):
|
||||||
|
"""产品属性+产品属性值管理业务关键字类"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
# ============ 产品属性管理方法 ============
|
||||||
|
|
||||||
|
@allure.step("创建产品属性")
|
||||||
|
def kw_joyhub_product_attr_type_create_post(self, name, type=2, id=0, status=1, remark=None, rank_num=None):
|
||||||
|
"""
|
||||||
|
创建产品属性业务关键字
|
||||||
|
:param id: 主键,新增为0
|
||||||
|
:param type: 属性类型:1-颜色属性(有色卡),2-普通属性
|
||||||
|
:param name: 属性名称
|
||||||
|
:param status: 状态 (1正常 2停用)
|
||||||
|
:param remark: 备注(可选)
|
||||||
|
:param rank_num: 排序号(可选)
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"创建产品属性 - name: {name}, type: {type}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"id": id,
|
||||||
|
"type": type,
|
||||||
|
"name": name,
|
||||||
|
"status": status
|
||||||
|
}
|
||||||
|
|
||||||
|
if remark is not None:
|
||||||
|
params["remark"] = remark
|
||||||
|
if rank_num is not None:
|
||||||
|
params["rankNum"] = rank_num
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_product_attr_type_create_post(**params)
|
||||||
|
obj_log.info(f"创建产品属性响应: {resp}")
|
||||||
|
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("删除产品属性")
|
||||||
|
def kw_joyhub_product_attr_type_delete_delete(self, product_attr_type_id):
|
||||||
|
"""
|
||||||
|
删除产品属性业务关键字
|
||||||
|
:param product_attr_type_id: 产品属性ID
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"删除产品属性 - product_attr_type_id: {product_attr_type_id}")
|
||||||
|
resp = self.kw_in_joyhub_product_attr_type_delete_delete(product_attr_type_id)
|
||||||
|
obj_log.info(f"删除产品属性响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("批量删除产品属性")
|
||||||
|
def kw_joyhub_product_attr_type_delete_list_delete(self, ids):
|
||||||
|
"""
|
||||||
|
批量删除产品属性业务关键字
|
||||||
|
:param ids: 产品属性ID列表
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"批量删除产品属性 - ids: {ids}")
|
||||||
|
resp = self.kw_in_joyhub_product_attr_type_delete_list_delete(ids)
|
||||||
|
obj_log.info(f"批量删除产品属性响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得产品属性详情")
|
||||||
|
def kw_joyhub_product_attr_type_get_get(self, product_attr_type_id):
|
||||||
|
"""
|
||||||
|
获得产品属性详情业务关键字
|
||||||
|
:param product_attr_type_id: 产品属性ID
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"获得产品属性详情 - product_attr_type_id: {product_attr_type_id}")
|
||||||
|
resp = self.kw_in_joyhub_product_attr_type_get_get(product_attr_type_id)
|
||||||
|
obj_log.info(f"获得产品属性详情响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得产品属性分页")
|
||||||
|
def kw_joyhub_product_attr_type_page_get(self, page_no=1, page_size=10, **kwargs):
|
||||||
|
"""
|
||||||
|
获得产品属性分页业务关键字
|
||||||
|
:param page_no: 页码
|
||||||
|
:param page_size: 每页大小
|
||||||
|
:param kwargs: 其他查询条件
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"获得产品属性分页 - page_no: {page_no}, page_size: {page_size}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"pageNo": page_no,
|
||||||
|
"pageSize": page_size
|
||||||
|
}
|
||||||
|
params.update(kwargs)
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_product_attr_type_page_get(**params)
|
||||||
|
obj_log.info(f"获得产品属性分页响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("更新产品属性")
|
||||||
|
def kw_joyhub_product_attr_type_update_put(self, product_attr_type_id, name, type=2, status=1, remark=None, rank_num=None):
|
||||||
|
"""
|
||||||
|
更新产品属性业务关键字
|
||||||
|
:param product_attr_type_id: 产品属性ID
|
||||||
|
:param name: 属性名称
|
||||||
|
:param type: 属性类型:1-颜色属性(有色卡),2-普通属性
|
||||||
|
:param status: 状态 (1正常 2停用)
|
||||||
|
:param remark: 备注(可选)
|
||||||
|
:param rank_num: 排序号(可选)
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"更新产品属性 - product_attr_type_id: {product_attr_type_id}, name: {name}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"id": product_attr_type_id,
|
||||||
|
"type": type,
|
||||||
|
"name": name,
|
||||||
|
"status": status
|
||||||
|
}
|
||||||
|
|
||||||
|
if remark is not None:
|
||||||
|
params["remark"] = remark
|
||||||
|
if rank_num is not None:
|
||||||
|
params["rankNum"] = rank_num
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_product_attr_type_update_put(**params)
|
||||||
|
obj_log.info(f"更新产品属性响应: {resp}")
|
||||||
|
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("修改产品属性状态")
|
||||||
|
def kw_joyhub_product_attr_type_change_status_put(self, product_attr_type_id, status):
|
||||||
|
"""
|
||||||
|
修改产品属性状态业务关键字
|
||||||
|
:param product_attr_type_id: 产品属性ID
|
||||||
|
:param status: 状态 (1正常 2停用)
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"修改产品属性状态 - product_attr_type_id: {product_attr_type_id}, status: {status}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"id": product_attr_type_id,
|
||||||
|
"status": status
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_product_attr_type_change_status_put(**params)
|
||||||
|
obj_log.info(f"修改产品属性状态响应: {resp}")
|
||||||
|
|
||||||
|
return resp
|
||||||
|
|
||||||
|
# ============ 产品属性值管理方法 ============
|
||||||
|
|
||||||
|
@allure.step("创建产品属性值")
|
||||||
|
def kw_joyhub_product_attr_data_create_post(self, product_attr_type_id, attr_value, id=0, color=None):
|
||||||
|
"""
|
||||||
|
创建产品属性值业务关键字
|
||||||
|
:param id: 主键ID,新增为0
|
||||||
|
:param product_attr_type_id: 关联产品属性表的主键ID
|
||||||
|
:param attr_value: 属性值名称
|
||||||
|
:param color: 色卡(可选,颜色属性类型时使用)
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"创建产品属性值 - product_attr_type_id: {product_attr_type_id}, attr_value: {attr_value}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"id": id,
|
||||||
|
"productAttrTypeId": product_attr_type_id,
|
||||||
|
"attrValue": attr_value
|
||||||
|
}
|
||||||
|
|
||||||
|
if color is not None:
|
||||||
|
params["color"] = color
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_product_attr_data_create_post(**params)
|
||||||
|
obj_log.info(f"创建产品属性值响应: {resp}")
|
||||||
|
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("删除产品属性值")
|
||||||
|
def kw_joyhub_product_attr_data_delete_delete(self, product_attr_data_id):
|
||||||
|
"""
|
||||||
|
删除产品属性值业务关键字
|
||||||
|
:param product_attr_data_id: 产品属性值ID
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"删除产品属性值 - product_attr_data_id: {product_attr_data_id}")
|
||||||
|
resp = self.kw_in_joyhub_product_attr_data_delete_delete(product_attr_data_id)
|
||||||
|
obj_log.info(f"删除产品属性值响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("批量删除产品属性值")
|
||||||
|
def kw_joyhub_product_attr_data_delete_list_delete(self, ids):
|
||||||
|
"""
|
||||||
|
批量删除产品属性值业务关键字
|
||||||
|
:param ids: 产品属性值ID列表
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"批量删除产品属性值 - ids: {ids}")
|
||||||
|
resp = self.kw_in_joyhub_product_attr_data_delete_list_delete(ids)
|
||||||
|
obj_log.info(f"批量删除产品属性值响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得产品属性值详情")
|
||||||
|
def kw_joyhub_product_attr_data_get_get(self, product_attr_data_id):
|
||||||
|
"""
|
||||||
|
获得产品属性值详情业务关键字
|
||||||
|
:param product_attr_data_id: 产品属性值ID
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"获得产品属性值详情 - product_attr_data_id: {product_attr_data_id}")
|
||||||
|
resp = self.kw_in_joyhub_product_attr_data_get_get(product_attr_data_id)
|
||||||
|
obj_log.info(f"获得产品属性值详情响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得产品属性值分页")
|
||||||
|
def kw_joyhub_product_attr_data_page_get(self, page_no=1, page_size=10, **kwargs):
|
||||||
|
"""
|
||||||
|
获得产品属性值分页业务关键字
|
||||||
|
:param page_no: 页码
|
||||||
|
:param page_size: 每页大小
|
||||||
|
:param kwargs: 其他查询条件
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"获得产品属性值分页 - page_no: {page_no}, page_size: {page_size}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"pageNo": page_no,
|
||||||
|
"pageSize": page_size
|
||||||
|
}
|
||||||
|
params.update(kwargs)
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_product_attr_data_page_get(**params)
|
||||||
|
obj_log.info(f"获得产品属性值分页响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("更新产品属性值")
|
||||||
|
def kw_joyhub_product_attr_data_update_put(self, product_attr_data_id, product_attr_type_id, attr_value, color=None):
|
||||||
|
"""
|
||||||
|
更新产品属性值业务关键字
|
||||||
|
:param product_attr_data_id: 产品属性值ID
|
||||||
|
:param product_attr_type_id: 关联产品属性表的主键ID
|
||||||
|
:param attr_value: 属性值名称
|
||||||
|
:param color: 色卡(可选,颜色属性类型时使用)
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"更新产品属性值 - product_attr_data_id: {product_attr_data_id}, attr_value: {attr_value}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"id": product_attr_data_id,
|
||||||
|
"productAttrTypeId": product_attr_type_id,
|
||||||
|
"attrValue": attr_value
|
||||||
|
}
|
||||||
|
|
||||||
|
if color is not None:
|
||||||
|
params["color"] = color
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_product_attr_data_update_put(**params)
|
||||||
|
obj_log.info(f"更新产品属性值响应: {resp}")
|
||||||
|
|
||||||
|
return resp
|
||||||
145
dulizhan/library/BusinessKw/JoyHub/ProductCateManage.py
Normal file
145
dulizhan/library/BusinessKw/JoyHub/ProductCateManage.py
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
产品分类管理业务关键字层
|
||||||
|
"""
|
||||||
|
import allure
|
||||||
|
from dulizhan.library.Dlizhan_interface import DlzhanInterface
|
||||||
|
from base_framework.public_tools import log
|
||||||
|
|
||||||
|
obj_log = log.get_logger()
|
||||||
|
|
||||||
|
|
||||||
|
class ProductCateManage(DlzhanInterface):
|
||||||
|
"""产品分类管理业务关键字类"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
@allure.step("创建产品分类")
|
||||||
|
def kw_joyhub_product_cate_create_post(self, cate_name, id=0, cate_type=1, status=1, rank_num=1):
|
||||||
|
"""
|
||||||
|
创建产品分类业务关键字
|
||||||
|
:param id: 主键ID,新增为0
|
||||||
|
:param cate_name: 产品分类名称
|
||||||
|
:param cate_type: 类型(普通产品=1,积分产品=2)
|
||||||
|
:param status: 状态 (1正常 2停用)
|
||||||
|
:param rank_num: 排序号
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"创建产品分类 - cate_name: {cate_name}, cate_type: {cate_type}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"id": id,
|
||||||
|
"cateName": cate_name,
|
||||||
|
"cateType": cate_type,
|
||||||
|
"status": status,
|
||||||
|
"rankNum": rank_num
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_product_cate_create_post(**params)
|
||||||
|
obj_log.info(f"创建产品分类响应: {resp}")
|
||||||
|
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("删除产品分类")
|
||||||
|
def kw_joyhub_product_cate_delete_delete(self, product_cate_id):
|
||||||
|
"""
|
||||||
|
删除产品分类业务关键字
|
||||||
|
:param product_cate_id: 产品分类ID
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"删除产品分类 - product_cate_id: {product_cate_id}")
|
||||||
|
resp = self.kw_in_joyhub_product_cate_delete_delete(product_cate_id)
|
||||||
|
obj_log.info(f"删除产品分类响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("批量删除产品分类")
|
||||||
|
def kw_joyhub_product_cate_delete_list_delete(self, ids):
|
||||||
|
"""
|
||||||
|
批量删除产品分类业务关键字
|
||||||
|
:param ids: 产品分类ID列表
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"批量删除产品分类 - ids: {ids}")
|
||||||
|
resp = self.kw_in_joyhub_product_cate_delete_list_delete(ids)
|
||||||
|
obj_log.info(f"批量删除产品分类响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得产品分类详情")
|
||||||
|
def kw_joyhub_product_cate_get_get(self, product_cate_id):
|
||||||
|
"""
|
||||||
|
获得产品分类详情业务关键字
|
||||||
|
:param product_cate_id: 产品分类ID
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"获得产品分类详情 - product_cate_id: {product_cate_id}")
|
||||||
|
resp = self.kw_in_joyhub_product_cate_get_get(product_cate_id)
|
||||||
|
obj_log.info(f"获得产品分类详情响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得产品分类分页")
|
||||||
|
def kw_joyhub_product_cate_page_get(self, page_no=1, page_size=10, **kwargs):
|
||||||
|
"""
|
||||||
|
获得产品分类分页业务关键字
|
||||||
|
:param page_no: 页码
|
||||||
|
:param page_size: 每页大小
|
||||||
|
:param kwargs: 其他查询条件
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"获得产品分类分页 - page_no: {page_no}, page_size: {page_size}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"pageNo": page_no,
|
||||||
|
"pageSize": page_size
|
||||||
|
}
|
||||||
|
params.update(kwargs)
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_product_cate_page_get(**params)
|
||||||
|
obj_log.info(f"获得产品分类分页响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("更新产品分类")
|
||||||
|
def kw_joyhub_product_cate_update_put(self, product_cate_id, cate_name, cate_type=1, status=1, rank_num=1):
|
||||||
|
"""
|
||||||
|
更新产品分类业务关键字
|
||||||
|
:param product_cate_id: 产品分类ID
|
||||||
|
:param cate_name: 产品分类名称
|
||||||
|
:param cate_type: 类型(普通产品=1,积分产品=2)
|
||||||
|
:param status: 状态 (1正常 2停用)
|
||||||
|
:param rank_num: 排序号
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"更新产品分类 - product_cate_id: {product_cate_id}, cate_name: {cate_name}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"id": product_cate_id,
|
||||||
|
"cateName": cate_name,
|
||||||
|
"cateType": cate_type,
|
||||||
|
"status": status,
|
||||||
|
"rankNum": rank_num
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_product_cate_update_put(**params)
|
||||||
|
obj_log.info(f"更新产品分类响应: {resp}")
|
||||||
|
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("修改产品分类启用/停用状态")
|
||||||
|
def kw_joyhub_product_cate_change_status_put(self, product_cate_id, status):
|
||||||
|
"""
|
||||||
|
修改产品分类启用/停用状态业务关键字
|
||||||
|
:param product_cate_id: 产品分类ID
|
||||||
|
:param status: 状态 (1正常 2停用)
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"修改产品分类状态 - product_cate_id: {product_cate_id}, status: {status}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"id": product_cate_id,
|
||||||
|
"status": status
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_product_cate_change_status_put(**params)
|
||||||
|
obj_log.info(f"修改产品分类状态响应: {resp}")
|
||||||
|
|
||||||
|
return resp
|
||||||
269
dulizhan/library/BusinessKw/JoyHub/ProductManage.py
Normal file
269
dulizhan/library/BusinessKw/JoyHub/ProductManage.py
Normal file
@@ -0,0 +1,269 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
产品管理业务关键字层
|
||||||
|
"""
|
||||||
|
import allure
|
||||||
|
from dulizhan.library.Dlizhan_interface import DlzhanInterface
|
||||||
|
from base_framework.public_tools import log
|
||||||
|
|
||||||
|
obj_log = log.get_logger()
|
||||||
|
|
||||||
|
|
||||||
|
class ProductManage(DlzhanInterface):
|
||||||
|
"""产品管理业务关键字类"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
@allure.step("创建产品")
|
||||||
|
def kw_joyhub_product_create_post(self, product_name, product_cate_id, shipping_template_id, route, intro,
|
||||||
|
brand_id, product_attrs, product_skus, id=0, product_type=1,
|
||||||
|
status=1, rank_num=None, seo_title=None, seo_keyword=None,
|
||||||
|
seo_description=None, single_user_exchange_limit=None,
|
||||||
|
single_product_exchange_limit=None, product_details=None):
|
||||||
|
"""
|
||||||
|
创建产品业务关键字
|
||||||
|
:param id: 主键,新增为0
|
||||||
|
:param product_type: 产品类型(普通产品=1,积分产品=2)
|
||||||
|
:param product_name: 产品名称
|
||||||
|
:param product_cate_id: 产品分类
|
||||||
|
:param shipping_template_id: 运费模板ID
|
||||||
|
:param route: 跳转路由
|
||||||
|
:param intro: 产品简介
|
||||||
|
:param brand_id: 品牌id
|
||||||
|
:param status: 状态(1上架,2下架)
|
||||||
|
:param rank_num: 序号(可选)
|
||||||
|
:param seo_title: SEO标题(可选)
|
||||||
|
:param seo_keyword: SEO关键词(可选)
|
||||||
|
:param seo_description: SEO描述(可选)
|
||||||
|
:param single_user_exchange_limit: 单用户兑换次数限制(可选)
|
||||||
|
:param single_product_exchange_limit: 单次兑换数量限制(可选)
|
||||||
|
:param product_attrs: 产品规格类型关联列表
|
||||||
|
:param product_skus: 产品规格列表
|
||||||
|
:param product_details: 产品详情列表(可选)
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"创建产品 - product_name: {product_name}, product_type: {product_type}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"id": id,
|
||||||
|
"productType": product_type,
|
||||||
|
"productName": product_name,
|
||||||
|
"productCateId": product_cate_id,
|
||||||
|
"shippingTemplateId": shipping_template_id,
|
||||||
|
"route": route,
|
||||||
|
"intro": intro,
|
||||||
|
"brandId": brand_id,
|
||||||
|
"status": status,
|
||||||
|
"productAttrs": product_attrs,
|
||||||
|
"productSkus": product_skus
|
||||||
|
}
|
||||||
|
|
||||||
|
if rank_num is not None:
|
||||||
|
params["rankNum"] = rank_num
|
||||||
|
if seo_title is not None:
|
||||||
|
params["seoTitle"] = seo_title
|
||||||
|
if seo_keyword is not None:
|
||||||
|
params["seoKeyword"] = seo_keyword
|
||||||
|
if seo_description is not None:
|
||||||
|
params["seoDescription"] = seo_description
|
||||||
|
if single_user_exchange_limit is not None:
|
||||||
|
params["singleUserExchangeLimit"] = single_user_exchange_limit
|
||||||
|
if single_product_exchange_limit is not None:
|
||||||
|
params["singleProductExchangeLimit"] = single_product_exchange_limit
|
||||||
|
if product_details is not None:
|
||||||
|
params["productDetails"] = product_details
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_product_create_post(**params)
|
||||||
|
obj_log.info(f"创建产品响应: {resp}")
|
||||||
|
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("删除产品")
|
||||||
|
def kw_joyhub_product_delete_delete(self, product_id):
|
||||||
|
"""
|
||||||
|
删除产品业务关键字
|
||||||
|
:param product_id: 产品ID
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"删除产品 - product_id: {product_id}")
|
||||||
|
resp = self.kw_in_joyhub_product_delete_delete(product_id)
|
||||||
|
obj_log.info(f"删除产品响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("批量删除产品")
|
||||||
|
def kw_joyhub_product_delete_list_delete(self, ids):
|
||||||
|
"""
|
||||||
|
批量删除产品业务关键字
|
||||||
|
:param ids: 产品ID列表
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"批量删除产品 - ids: {ids}")
|
||||||
|
resp = self.kw_in_joyhub_product_delete_list_delete(ids)
|
||||||
|
obj_log.info(f"批量删除产品响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得产品详情")
|
||||||
|
def kw_joyhub_product_get_get(self, product_id):
|
||||||
|
"""
|
||||||
|
获得产品详情业务关键字
|
||||||
|
:param product_id: 产品ID
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"获得产品详情 - product_id: {product_id}")
|
||||||
|
resp = self.kw_in_joyhub_product_get_get(product_id)
|
||||||
|
obj_log.info(f"获得产品详情响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得产品分页")
|
||||||
|
def kw_joyhub_product_page_get(self, page_no=1, page_size=10, **kwargs):
|
||||||
|
"""
|
||||||
|
获得产品分页业务关键字
|
||||||
|
:param page_no: 页码
|
||||||
|
:param page_size: 每页大小
|
||||||
|
:param kwargs: 其他查询条件
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"获得产品分页 - page_no: {page_no}, page_size: {page_size}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"pageNo": page_no,
|
||||||
|
"pageSize": page_size
|
||||||
|
}
|
||||||
|
params.update(kwargs)
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_product_page_get(**params)
|
||||||
|
obj_log.info(f"获得产品分页响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得产品规格类型关联列表")
|
||||||
|
def kw_joyhub_product_product_attr_list_by_product_id_get(self, product_id):
|
||||||
|
"""
|
||||||
|
获得产品规格类型关联列表业务关键字
|
||||||
|
:param product_id: 产品ID
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"获得产品规格类型关联列表 - product_id: {product_id}")
|
||||||
|
resp = self.kw_in_joyhub_product_product_attr_list_by_product_id_get(product_id)
|
||||||
|
obj_log.info(f"获得产品规格类型关联列表响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得产品详情列表")
|
||||||
|
def kw_joyhub_product_product_detail_list_by_product_id_get(self, product_id):
|
||||||
|
"""
|
||||||
|
获得产品详情列表业务关键字
|
||||||
|
:param product_id: 产品ID
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"获得产品详情列表 - product_id: {product_id}")
|
||||||
|
resp = self.kw_in_joyhub_product_product_detail_list_by_product_id_get(product_id)
|
||||||
|
obj_log.info(f"获得产品详情列表响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得产品规格列表")
|
||||||
|
def kw_joyhub_product_product_sku_list_by_product_id_get(self, product_id):
|
||||||
|
"""
|
||||||
|
获得产品规格列表业务关键字
|
||||||
|
:param product_id: 产品ID
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"获得产品规格列表 - product_id: {product_id}")
|
||||||
|
resp = self.kw_in_joyhub_product_product_sku_list_by_product_id_get(product_id)
|
||||||
|
obj_log.info(f"获得产品规格列表响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得产品及规格列表-优惠券中使用")
|
||||||
|
def kw_joyhub_product_product_sku_list_get(self, **kwargs):
|
||||||
|
"""
|
||||||
|
获得产品及规格列表-优惠券中使用业务关键字
|
||||||
|
:param kwargs: 查询条件
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"获得产品及规格列表 - params: {kwargs}")
|
||||||
|
resp = self.kw_in_joyhub_product_product_sku_list_get(**kwargs)
|
||||||
|
obj_log.info(f"获得产品及规格列表响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("更新产品")
|
||||||
|
def kw_joyhub_product_update_put(self, product_id, product_name, product_cate_id, shipping_template_id, route, intro,
|
||||||
|
brand_id, product_attrs, product_skus, product_type=1,
|
||||||
|
status=1, rank_num=None, seo_title=None, seo_keyword=None,
|
||||||
|
seo_description=None, single_user_exchange_limit=None,
|
||||||
|
single_product_exchange_limit=None, product_details=None):
|
||||||
|
"""
|
||||||
|
更新产品业务关键字
|
||||||
|
:param product_id: 产品ID
|
||||||
|
:param product_type: 产品类型(普通产品=1,积分产品=2)
|
||||||
|
:param product_name: 产品名称
|
||||||
|
:param product_cate_id: 产品分类
|
||||||
|
:param shipping_template_id: 运费模板ID
|
||||||
|
:param route: 跳转路由
|
||||||
|
:param intro: 产品简介
|
||||||
|
:param brand_id: 品牌id
|
||||||
|
:param status: 状态(1上架,2下架)
|
||||||
|
:param rank_num: 序号(可选)
|
||||||
|
:param seo_title: SEO标题(可选)
|
||||||
|
:param seo_keyword: SEO关键词(可选)
|
||||||
|
:param seo_description: SEO描述(可选)
|
||||||
|
:param single_user_exchange_limit: 单用户兑换次数限制(可选)
|
||||||
|
:param single_product_exchange_limit: 单次兑换数量限制(可选)
|
||||||
|
:param product_attrs: 产品规格类型关联列表
|
||||||
|
:param product_skus: 产品规格列表
|
||||||
|
:param product_details: 产品详情列表(可选)
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"更新产品 - product_id: {product_id}, product_name: {product_name}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"id": product_id,
|
||||||
|
"productType": product_type,
|
||||||
|
"productName": product_name,
|
||||||
|
"productCateId": product_cate_id,
|
||||||
|
"shippingTemplateId": shipping_template_id,
|
||||||
|
"route": route,
|
||||||
|
"intro": intro,
|
||||||
|
"brandId": brand_id,
|
||||||
|
"status": status,
|
||||||
|
"productAttrs": product_attrs,
|
||||||
|
"productSkus": product_skus
|
||||||
|
}
|
||||||
|
|
||||||
|
if rank_num is not None:
|
||||||
|
params["rankNum"] = rank_num
|
||||||
|
if seo_title is not None:
|
||||||
|
params["seoTitle"] = seo_title
|
||||||
|
if seo_keyword is not None:
|
||||||
|
params["seoKeyword"] = seo_keyword
|
||||||
|
if seo_description is not None:
|
||||||
|
params["seoDescription"] = seo_description
|
||||||
|
if single_user_exchange_limit is not None:
|
||||||
|
params["singleUserExchangeLimit"] = single_user_exchange_limit
|
||||||
|
if single_product_exchange_limit is not None:
|
||||||
|
params["singleProductExchangeLimit"] = single_product_exchange_limit
|
||||||
|
if product_details is not None:
|
||||||
|
params["productDetails"] = product_details
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_product_update_put(**params)
|
||||||
|
obj_log.info(f"更新产品响应: {resp}")
|
||||||
|
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("批量上下架产品")
|
||||||
|
def kw_joyhub_product_change_status_put(self, ids, status):
|
||||||
|
"""
|
||||||
|
批量上下架产品业务关键字
|
||||||
|
:param ids: 产品ID列表
|
||||||
|
:param status: 状态(1上架,2下架)
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"批量上下架产品 - ids: {ids}, status: {status}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"ids": ids,
|
||||||
|
"status": status
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_product_change_status_put(**params)
|
||||||
|
obj_log.info(f"批量上下架产品响应: {resp}")
|
||||||
|
|
||||||
|
return resp
|
||||||
@@ -0,0 +1,124 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
支付页产品推荐业务关键字层
|
||||||
|
"""
|
||||||
|
import allure
|
||||||
|
from dulizhan.library.Dlizhan_interface import DlzhanInterface
|
||||||
|
from base_framework.public_tools import log
|
||||||
|
|
||||||
|
obj_log = log.get_logger()
|
||||||
|
|
||||||
|
|
||||||
|
class ProductPaymentRecommendManage(DlzhanInterface):
|
||||||
|
"""支付页产品推荐业务关键字类"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
@allure.step("修改支付页产品推荐排序号")
|
||||||
|
def kw_joyhub_product_payment_recommend_change_rank_num_put(self, recommend_id, rank_num):
|
||||||
|
"""
|
||||||
|
修改支付页产品推荐排序号业务关键字
|
||||||
|
:param recommend_id: 推荐ID
|
||||||
|
:param rank_num: 排序号
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"修改支付页产品推荐排序号 - recommend_id: {recommend_id}, rank_num: {rank_num}")
|
||||||
|
resp = self.kw_in_joyhub_product_payment_recommend_change_rank_num_put(id=recommend_id, rankNum=rank_num)
|
||||||
|
obj_log.info(f"修改支付页产品推荐排序号响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("修改支付页产品推荐状态")
|
||||||
|
def kw_joyhub_product_payment_recommend_change_status_put(self, recommend_id, recommend_status):
|
||||||
|
"""
|
||||||
|
修改支付页产品推荐状态业务关键字
|
||||||
|
:param recommend_id: 推荐ID
|
||||||
|
:param recommend_status: 推荐状态
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"修改支付页产品推荐状态 - recommend_id: {recommend_id}, recommend_status: {recommend_status}")
|
||||||
|
resp = self.kw_in_joyhub_product_payment_recommend_change_status_put(id=recommend_id, recommendStatus=recommend_status)
|
||||||
|
obj_log.info(f"修改支付页产品推荐状态响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("创建支付页产品推荐")
|
||||||
|
def kw_joyhub_product_payment_recommend_create_post(self, product_ids, recommend_id=None):
|
||||||
|
"""
|
||||||
|
创建支付页产品推荐业务关键字
|
||||||
|
:param product_ids: 产品ID列表
|
||||||
|
:param recommend_id: 推荐ID
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"创建支付页产品推荐 - product_ids: {product_ids}")
|
||||||
|
params = {"productIds": product_ids}
|
||||||
|
if recommend_id is not None:
|
||||||
|
params["id"] = recommend_id
|
||||||
|
resp = self.kw_in_joyhub_product_payment_recommend_create_post(**params)
|
||||||
|
obj_log.info(f"创建支付页产品推荐响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("删除支付页产品推荐")
|
||||||
|
def kw_joyhub_product_payment_recommend_delete_delete(self, recommend_id):
|
||||||
|
"""
|
||||||
|
删除支付页产品推荐业务关键字
|
||||||
|
:param recommend_id: 推荐ID
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"删除支付页产品推荐 - recommend_id: {recommend_id}")
|
||||||
|
resp = self.kw_in_joyhub_product_payment_recommend_delete_delete(recommend_id)
|
||||||
|
obj_log.info(f"删除支付页产品推荐响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("批量删除支付页产品推荐")
|
||||||
|
def kw_joyhub_product_payment_recommend_delete_list_delete(self, ids):
|
||||||
|
"""
|
||||||
|
批量删除支付页产品推荐业务关键字
|
||||||
|
:param ids: 推荐ID列表
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"批量删除支付页产品推荐 - ids: {ids}")
|
||||||
|
resp = self.kw_in_joyhub_product_payment_recommend_delete_list_delete(ids)
|
||||||
|
obj_log.info(f"批量删除支付页产品推荐响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得支付页产品推荐分页")
|
||||||
|
def kw_joyhub_product_payment_recommend_page_get(self, page_no=1, page_size=10, **kwargs):
|
||||||
|
"""
|
||||||
|
获得支付页产品推荐分页业务关键字
|
||||||
|
:param page_no: 页码
|
||||||
|
:param page_size: 每页大小
|
||||||
|
:param kwargs: 其他查询条件
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"获得支付页产品推荐分页 - page_no: {page_no}, page_size: {page_size}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"pageNo": page_no,
|
||||||
|
"pageSize": page_size
|
||||||
|
}
|
||||||
|
params.update(kwargs)
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_product_payment_recommend_page_get(**params)
|
||||||
|
obj_log.info(f"获得支付页产品推荐分页响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得C端支付页产品推荐分页")
|
||||||
|
def kw_joyhub_web_product_payment_recommend_page_get(self, page_no=1, page_size=10, **kwargs):
|
||||||
|
"""
|
||||||
|
获得支付页产品推荐分页业务关键字
|
||||||
|
:param page_no: 页码
|
||||||
|
:param page_size: 每页大小
|
||||||
|
:param kwargs: 其他查询条件
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info(f"获得支付页产品推荐分页 - page_no: {page_no}, page_size: {page_size}")
|
||||||
|
|
||||||
|
params = {
|
||||||
|
"pageNo": page_no,
|
||||||
|
"pageSize": page_size
|
||||||
|
}
|
||||||
|
params.update(kwargs)
|
||||||
|
|
||||||
|
resp = self.kw_in_joyhub_web_product_payment_recommend_page_get(**params)
|
||||||
|
obj_log.info(f"获得支付页产品推荐分页响应: {resp}")
|
||||||
|
return resp
|
||||||
27
dulizhan/library/BusinessKw/JoyHubC/AppVersionManage.py
Normal file
27
dulizhan/library/BusinessKw/JoyHubC/AppVersionManage.py
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
JoyHub C端APP版本业务关键字层
|
||||||
|
"""
|
||||||
|
import allure
|
||||||
|
from dulizhan.library.BusinessKw.JoyHubC.LoginManage import JoyHubCLoginManage
|
||||||
|
from base_framework.public_tools import log
|
||||||
|
|
||||||
|
obj_log = log.get_logger()
|
||||||
|
|
||||||
|
|
||||||
|
class JoyHubCAppVersionManage(JoyHubCLoginManage):
|
||||||
|
"""JoyHub C端APP版本业务关键字类"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
@allure.step("获取APP版本列表")
|
||||||
|
def kw_joyhub_c_web_appversion_page_get(self, **kwargs):
|
||||||
|
"""
|
||||||
|
获取APP版本列表业务关键字
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info("获取APP版本列表")
|
||||||
|
resp = self.kw_in_joyhub_c_web_appversion_page_get(**kwargs)
|
||||||
|
obj_log.info(f"获取APP版本列表响应: {resp}")
|
||||||
|
return resp
|
||||||
38
dulizhan/library/BusinessKw/JoyHubC/BannerManage.py
Normal file
38
dulizhan/library/BusinessKw/JoyHubC/BannerManage.py
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
JoyHub C端Banner信息业务关键字层
|
||||||
|
"""
|
||||||
|
import allure
|
||||||
|
from dulizhan.library.BusinessKw.JoyHubC.LoginManage import JoyHubCLoginManage
|
||||||
|
from base_framework.public_tools import log
|
||||||
|
|
||||||
|
obj_log = log.get_logger()
|
||||||
|
|
||||||
|
|
||||||
|
class JoyHubCBannerManage(JoyHubCLoginManage):
|
||||||
|
"""JoyHub C端Banner信息业务关键字类"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
@allure.step("获得Banner管理")
|
||||||
|
def kw_joyhub_c_banner_get_get(self, **kwargs):
|
||||||
|
"""
|
||||||
|
获得Banner管理业务关键字
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info("获得Banner管理")
|
||||||
|
resp = self.kw_in_joyhub_c_banner_get_get(**kwargs)
|
||||||
|
obj_log.info(f"获得Banner管理响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得Banner管理分页")
|
||||||
|
def kw_joyhub_c_banner_page_get(self, **kwargs):
|
||||||
|
"""
|
||||||
|
获得Banner管理分页业务关键字
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info("获得Banner管理分页")
|
||||||
|
resp = self.kw_in_joyhub_c_banner_page_get(**kwargs)
|
||||||
|
obj_log.info(f"获得Banner管理分页响应: {resp}")
|
||||||
|
return resp
|
||||||
27
dulizhan/library/BusinessKw/JoyHubC/BlogCateManage.py
Normal file
27
dulizhan/library/BusinessKw/JoyHubC/BlogCateManage.py
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
JoyHub C端blog分类业务关键字层
|
||||||
|
"""
|
||||||
|
import allure
|
||||||
|
from dulizhan.library.BusinessKw.JoyHubC.LoginManage import JoyHubCLoginManage
|
||||||
|
from base_framework.public_tools import log
|
||||||
|
|
||||||
|
obj_log = log.get_logger()
|
||||||
|
|
||||||
|
|
||||||
|
class JoyHubCBlogCateManage(JoyHubCLoginManage):
|
||||||
|
"""JoyHub C端blog分类业务关键字类"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
@allure.step("获得blog分类列表")
|
||||||
|
def kw_joyhub_c_blog_cate_list_get(self, **kwargs):
|
||||||
|
"""
|
||||||
|
获得blog分类列表业务关键字
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info("获得blog分类列表")
|
||||||
|
resp = self.kw_in_joyhub_c_blog_cate_list_get(**kwargs)
|
||||||
|
obj_log.info(f"获得blog分类列表响应: {resp}")
|
||||||
|
return resp
|
||||||
49
dulizhan/library/BusinessKw/JoyHubC/BlogManage.py
Normal file
49
dulizhan/library/BusinessKw/JoyHubC/BlogManage.py
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
JoyHub C端blog信息业务关键字层
|
||||||
|
"""
|
||||||
|
import allure
|
||||||
|
from dulizhan.library.BusinessKw.JoyHubC.LoginManage import JoyHubCLoginManage
|
||||||
|
from base_framework.public_tools import log
|
||||||
|
|
||||||
|
obj_log = log.get_logger()
|
||||||
|
|
||||||
|
|
||||||
|
class JoyHubCBlogManage(JoyHubCLoginManage):
|
||||||
|
"""JoyHub C端blog信息业务关键字类"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
@allure.step("获得blog详情")
|
||||||
|
def kw_joyhub_c_blog_get_detail_get(self, **kwargs):
|
||||||
|
"""
|
||||||
|
获得blog详情业务关键字
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info("获得blog详情")
|
||||||
|
resp = self.kw_in_joyhub_c_blog_get_detail_get(**kwargs)
|
||||||
|
obj_log.info(f"获得blog详情响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得blog下一条")
|
||||||
|
def kw_joyhub_c_blog_get_next_get(self, **kwargs):
|
||||||
|
"""
|
||||||
|
获得blog下一条业务关键字
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info("获得blog下一条")
|
||||||
|
resp = self.kw_in_joyhub_c_blog_get_next_get(**kwargs)
|
||||||
|
obj_log.info(f"获得blog下一条响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得blog管理分页")
|
||||||
|
def kw_joyhub_c_blog_page_get(self, **kwargs):
|
||||||
|
"""
|
||||||
|
获得blog管理分页业务关键字
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info("获得blog管理分页")
|
||||||
|
resp = self.kw_in_joyhub_c_blog_page_get(**kwargs)
|
||||||
|
obj_log.info(f"获得blog管理分页响应: {resp}")
|
||||||
|
return resp
|
||||||
27
dulizhan/library/BusinessKw/JoyHubC/CooperationManage.py
Normal file
27
dulizhan/library/BusinessKw/JoyHubC/CooperationManage.py
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
JoyHub C端合作联系业务关键字层
|
||||||
|
"""
|
||||||
|
import allure
|
||||||
|
from dulizhan.library.BusinessKw.JoyHubC.LoginManage import JoyHubCLoginManage
|
||||||
|
from base_framework.public_tools import log
|
||||||
|
|
||||||
|
obj_log = log.get_logger()
|
||||||
|
|
||||||
|
|
||||||
|
class JoyHubCCooperationManage(JoyHubCLoginManage):
|
||||||
|
"""JoyHub C端合作联系业务关键字类"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
@allure.step("提交合作联系信息")
|
||||||
|
def kw_joyhub_c_cooperation_create_post(self, **kwargs):
|
||||||
|
"""
|
||||||
|
提交合作联系信息业务关键字
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info("提交合作联系信息")
|
||||||
|
resp = self.kw_in_joyhub_c_cooperation_create_post(**kwargs)
|
||||||
|
obj_log.info(f"提交合作联系信息响应: {resp}")
|
||||||
|
return resp
|
||||||
38
dulizhan/library/BusinessKw/JoyHubC/DownloadQrcodeManage.py
Normal file
38
dulizhan/library/BusinessKw/JoyHubC/DownloadQrcodeManage.py
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
JoyHub C端二维码访问统计业务关键字层
|
||||||
|
"""
|
||||||
|
import allure
|
||||||
|
from dulizhan.library.BusinessKw.JoyHubC.LoginManage import JoyHubCLoginManage
|
||||||
|
from base_framework.public_tools import log
|
||||||
|
|
||||||
|
obj_log = log.get_logger()
|
||||||
|
|
||||||
|
|
||||||
|
class JoyHubCDownloadQrcodeManage(JoyHubCLoginManage):
|
||||||
|
"""JoyHub C端二维码访问统计业务关键字类"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
@allure.step("获取二维码信息")
|
||||||
|
def kw_joyhub_c_download_qrcode_get_get(self, **kwargs):
|
||||||
|
"""
|
||||||
|
获取二维码信息业务关键字
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info("获取二维码信息")
|
||||||
|
resp = self.kw_in_joyhub_c_download_qrcode_get_get(**kwargs)
|
||||||
|
obj_log.info(f"获取二维码信息响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("增加二维码访问/点击次数")
|
||||||
|
def kw_joyhub_c_download_qrcode_increment_post(self, **kwargs):
|
||||||
|
"""
|
||||||
|
增加二维码访问/点击次数业务关键字
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info("增加二维码访问/点击次数")
|
||||||
|
resp = self.kw_in_joyhub_c_download_qrcode_increment_post(**kwargs)
|
||||||
|
obj_log.info(f"增加二维码访问/点击次数响应: {resp}")
|
||||||
|
return resp
|
||||||
27
dulizhan/library/BusinessKw/JoyHubC/FaqContactUsManage.py
Normal file
27
dulizhan/library/BusinessKw/JoyHubC/FaqContactUsManage.py
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
JoyHub C端FAQ联系我们业务关键字层
|
||||||
|
"""
|
||||||
|
import allure
|
||||||
|
from dulizhan.library.BusinessKw.JoyHubC.LoginManage import JoyHubCLoginManage
|
||||||
|
from base_framework.public_tools import log
|
||||||
|
|
||||||
|
obj_log = log.get_logger()
|
||||||
|
|
||||||
|
|
||||||
|
class JoyHubCFaqContactUsManage(JoyHubCLoginManage):
|
||||||
|
"""JoyHub C端FAQ联系我们业务关键字类"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
@allure.step("提交FAQ联系信息")
|
||||||
|
def kw_joyhub_c_faq_contact_us_create_post(self, **kwargs):
|
||||||
|
"""
|
||||||
|
提交FAQ联系信息业务关键字
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info("提交FAQ联系信息")
|
||||||
|
resp = self.kw_in_joyhub_c_faq_contact_us_create_post(**kwargs)
|
||||||
|
obj_log.info(f"提交FAQ联系信息响应: {resp}")
|
||||||
|
return resp
|
||||||
38
dulizhan/library/BusinessKw/JoyHubC/FaqManage.py
Normal file
38
dulizhan/library/BusinessKw/JoyHubC/FaqManage.py
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
JoyHub C端FAQ业务关键字层
|
||||||
|
"""
|
||||||
|
import allure
|
||||||
|
from dulizhan.library.BusinessKw.JoyHubC.LoginManage import JoyHubCLoginManage
|
||||||
|
from base_framework.public_tools import log
|
||||||
|
|
||||||
|
obj_log = log.get_logger()
|
||||||
|
|
||||||
|
|
||||||
|
class JoyHubCFaqManage(JoyHubCLoginManage):
|
||||||
|
"""JoyHub C端FAQ业务关键字类"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
@allure.step("获得FAQ分类树")
|
||||||
|
def kw_joyhub_c_faq_cate_list_get(self, **kwargs):
|
||||||
|
"""
|
||||||
|
获得FAQ分类树业务关键字
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info("获得FAQ分类树")
|
||||||
|
resp = self.kw_in_joyhub_c_faq_cate_list_get(**kwargs)
|
||||||
|
obj_log.info(f"获得FAQ分类树响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得FAQ列表")
|
||||||
|
def kw_joyhub_c_faq_list_get(self, **kwargs):
|
||||||
|
"""
|
||||||
|
获得FAQ列表业务关键字
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info("获得FAQ列表")
|
||||||
|
resp = self.kw_in_joyhub_c_faq_list_get(**kwargs)
|
||||||
|
obj_log.info(f"获得FAQ列表响应: {resp}")
|
||||||
|
return resp
|
||||||
60
dulizhan/library/BusinessKw/JoyHubC/LikeInfoManage.py
Normal file
60
dulizhan/library/BusinessKw/JoyHubC/LikeInfoManage.py
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
JoyHub C端点赞记录业务关键字层
|
||||||
|
"""
|
||||||
|
import allure
|
||||||
|
from dulizhan.library.BusinessKw.JoyHubC.LoginManage import JoyHubCLoginManage
|
||||||
|
from base_framework.public_tools import log
|
||||||
|
|
||||||
|
obj_log = log.get_logger()
|
||||||
|
|
||||||
|
|
||||||
|
class JoyHubCLikeInfoManage(JoyHubCLoginManage):
|
||||||
|
"""JoyHub C端点赞记录业务关键字类"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
@allure.step("创建点赞记录")
|
||||||
|
def kw_joyhub_c_like_info_create_post(self, **kwargs):
|
||||||
|
"""
|
||||||
|
创建点赞记录业务关键字
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info("创建点赞记录")
|
||||||
|
resp = self.kw_in_joyhub_c_like_info_create_post(**kwargs)
|
||||||
|
obj_log.info(f"创建点赞记录响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("取消点赞")
|
||||||
|
def kw_joyhub_c_like_info_delete_post(self, **kwargs):
|
||||||
|
"""
|
||||||
|
取消点赞业务关键字
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info("取消点赞")
|
||||||
|
resp = self.kw_in_joyhub_c_like_info_delete_post(**kwargs)
|
||||||
|
obj_log.info(f"取消点赞响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得点赞记录")
|
||||||
|
def kw_joyhub_c_like_info_get_get(self, **kwargs):
|
||||||
|
"""
|
||||||
|
获得点赞记录业务关键字
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info("获得点赞记录")
|
||||||
|
resp = self.kw_in_joyhub_c_like_info_get_get(**kwargs)
|
||||||
|
obj_log.info(f"获得点赞记录响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得点赞记录分页")
|
||||||
|
def kw_joyhub_c_like_info_page_get(self, **kwargs):
|
||||||
|
"""
|
||||||
|
获得点赞记录分页业务关键字
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info("获得点赞记录分页")
|
||||||
|
resp = self.kw_in_joyhub_c_like_info_page_get(**kwargs)
|
||||||
|
obj_log.info(f"获得点赞记录分页响应: {resp}")
|
||||||
|
return resp
|
||||||
84
dulizhan/library/BusinessKw/JoyHubC/LoginManage.py
Normal file
84
dulizhan/library/BusinessKw/JoyHubC/LoginManage.py
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
import os
|
||||||
|
import re
|
||||||
|
import time
|
||||||
|
|
||||||
|
import allure
|
||||||
|
|
||||||
|
from base_framework.public_tools import log
|
||||||
|
from dulizhan.library.Dlizhan_interface import DlzhanInterface
|
||||||
|
|
||||||
|
obj_log = log.get_logger()
|
||||||
|
|
||||||
|
|
||||||
|
class JoyHubCLoginManage(DlzhanInterface):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
test_url = self._read_robot_variable("joyhub_c_test_url")
|
||||||
|
if test_url:
|
||||||
|
self.joyhub_c_frontend_url = test_url
|
||||||
|
|
||||||
|
def _read_robot_variable(self, var_name):
|
||||||
|
robot_file_path = os.path.join(
|
||||||
|
os.path.dirname(__file__),
|
||||||
|
'../../../test_case/Resource/AdapterKws/hh-qa.robot'
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
with open(robot_file_path, 'r', encoding='utf-8') as f:
|
||||||
|
content = f.read()
|
||||||
|
pattern = r'\$\{' + re.escape(var_name) + r'\}\s+(\S+)'
|
||||||
|
match = re.search(pattern, content)
|
||||||
|
if match:
|
||||||
|
return match.group(1)
|
||||||
|
except Exception as e:
|
||||||
|
obj_log.error("读取robot配置文件失败: {}".format(str(e)))
|
||||||
|
return None
|
||||||
|
|
||||||
|
@allure.step("获取JoyHub C端邮箱验证码")
|
||||||
|
def kw_joyhub_c_get_email_code(self, email=None, code_pattern=r'\d{4,8}'):
|
||||||
|
email = email or self._read_robot_variable("joyhub_c_login_email")
|
||||||
|
if not email:
|
||||||
|
raise Exception("C端登录邮箱不能为空,请检查 joyhub_c_login_email 配置")
|
||||||
|
|
||||||
|
obj_log.info("获取JoyHub C端邮箱验证码 - email: {}".format(email))
|
||||||
|
code = self.kw_in_joyhub_c_get_email_code(email, code_pattern)
|
||||||
|
obj_log.info("获取JoyHub C端邮箱验证码成功")
|
||||||
|
return code
|
||||||
|
|
||||||
|
@allure.step("JoyHub C端登录")
|
||||||
|
def kw_joyhub_c_login(self, path=None, email=None, code=None, is_check='true', **kwargs):
|
||||||
|
email = email or self._read_robot_variable("joyhub_c_login_email")
|
||||||
|
path = path or self._read_robot_variable("joyhub_c_login_path")
|
||||||
|
if not email:
|
||||||
|
raise Exception("C端登录邮箱不能为空,请检查 joyhub_c_login_email 配置")
|
||||||
|
if not path:
|
||||||
|
raise Exception("C端登录接口路径不能为空,请检查 joyhub_c_login_path 配置")
|
||||||
|
|
||||||
|
code = code or "123456"
|
||||||
|
params = {
|
||||||
|
"email": email,
|
||||||
|
"valid_code": code,
|
||||||
|
"sys_type": "windows",
|
||||||
|
"app_channel": "5",
|
||||||
|
"lang": "en",
|
||||||
|
"client_time": str(int(time.time()))
|
||||||
|
}
|
||||||
|
params.update(kwargs)
|
||||||
|
|
||||||
|
obj_log.info("JoyHub C端登录 - email: {}, path: {}".format(email, path))
|
||||||
|
resp = self.kw_in_joyhub_c_login_post(path=path, is_check=is_check, **params)
|
||||||
|
|
||||||
|
data = resp.get('data') if isinstance(resp, dict) else None
|
||||||
|
token = None
|
||||||
|
if isinstance(data, dict):
|
||||||
|
token = data.get('accessToken') or data.get('access_token') or data.get('token')
|
||||||
|
token = token or resp.get('accessToken') if isinstance(resp, dict) else token
|
||||||
|
token = token or resp.get('access_token') if isinstance(resp, dict) else token
|
||||||
|
token = token or resp.get('token') if isinstance(resp, dict) else token
|
||||||
|
|
||||||
|
if token:
|
||||||
|
self.set_joyhub_c_token(token)
|
||||||
|
obj_log.info("JoyHub C端登录成功,Token已写入当前实例")
|
||||||
|
else:
|
||||||
|
obj_log.warning("JoyHub C端登录响应中未解析到Token")
|
||||||
|
return resp
|
||||||
27
dulizhan/library/BusinessKw/JoyHubC/NewsCateManage.py
Normal file
27
dulizhan/library/BusinessKw/JoyHubC/NewsCateManage.py
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
JoyHub C端news分类业务关键字层
|
||||||
|
"""
|
||||||
|
import allure
|
||||||
|
from dulizhan.library.BusinessKw.JoyHubC.LoginManage import JoyHubCLoginManage
|
||||||
|
from base_framework.public_tools import log
|
||||||
|
|
||||||
|
obj_log = log.get_logger()
|
||||||
|
|
||||||
|
|
||||||
|
class JoyHubCNewsCateManage(JoyHubCLoginManage):
|
||||||
|
"""JoyHub C端news分类业务关键字类"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
@allure.step("获得news分类列表")
|
||||||
|
def kw_joyhub_c_news_cate_list_get(self, **kwargs):
|
||||||
|
"""
|
||||||
|
获得news分类列表业务关键字
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info("获得news分类列表")
|
||||||
|
resp = self.kw_in_joyhub_c_news_cate_list_get(**kwargs)
|
||||||
|
obj_log.info(f"获得news分类列表响应: {resp}")
|
||||||
|
return resp
|
||||||
49
dulizhan/library/BusinessKw/JoyHubC/NewsManage.py
Normal file
49
dulizhan/library/BusinessKw/JoyHubC/NewsManage.py
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
JoyHub C端news管理业务关键字层
|
||||||
|
"""
|
||||||
|
import allure
|
||||||
|
from dulizhan.library.BusinessKw.JoyHubC.LoginManage import JoyHubCLoginManage
|
||||||
|
from base_framework.public_tools import log
|
||||||
|
|
||||||
|
obj_log = log.get_logger()
|
||||||
|
|
||||||
|
|
||||||
|
class JoyHubCNewsManage(JoyHubCLoginManage):
|
||||||
|
"""JoyHub C端news管理业务关键字类"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
@allure.step("获得news详情")
|
||||||
|
def kw_joyhub_c_news_get_detail_get(self, **kwargs):
|
||||||
|
"""
|
||||||
|
获得news详情业务关键字
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info("获得news详情")
|
||||||
|
resp = self.kw_in_joyhub_c_news_get_detail_get(**kwargs)
|
||||||
|
obj_log.info(f"获得news详情响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得news下一条")
|
||||||
|
def kw_joyhub_c_news_get_next_get(self, **kwargs):
|
||||||
|
"""
|
||||||
|
获得news下一条业务关键字
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info("获得news下一条")
|
||||||
|
resp = self.kw_in_joyhub_c_news_get_next_get(**kwargs)
|
||||||
|
obj_log.info(f"获得news下一条响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得news管理分页")
|
||||||
|
def kw_joyhub_c_news_page_get(self, **kwargs):
|
||||||
|
"""
|
||||||
|
获得news管理分页业务关键字
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info("获得news管理分页")
|
||||||
|
resp = self.kw_in_joyhub_c_news_page_get(**kwargs)
|
||||||
|
obj_log.info(f"获得news管理分页响应: {resp}")
|
||||||
|
return resp
|
||||||
38
dulizhan/library/BusinessKw/JoyHubC/ProductManage.py
Normal file
38
dulizhan/library/BusinessKw/JoyHubC/ProductManage.py
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
JoyHub C端产品业务关键字层
|
||||||
|
"""
|
||||||
|
import allure
|
||||||
|
from dulizhan.library.BusinessKw.JoyHubC.LoginManage import JoyHubCLoginManage
|
||||||
|
from base_framework.public_tools import log
|
||||||
|
|
||||||
|
obj_log = log.get_logger()
|
||||||
|
|
||||||
|
|
||||||
|
class JoyHubCProductManage(JoyHubCLoginManage):
|
||||||
|
"""JoyHub C端产品业务关键字类"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
@allure.step("产品详情")
|
||||||
|
def kw_joyhub_c_product_get_get(self, **kwargs):
|
||||||
|
"""
|
||||||
|
产品详情业务关键字
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info("产品详情")
|
||||||
|
resp = self.kw_in_joyhub_c_product_get_get(**kwargs)
|
||||||
|
obj_log.info(f"产品详情响应: {resp}")
|
||||||
|
return resp
|
||||||
|
|
||||||
|
@allure.step("获得产品分页")
|
||||||
|
def kw_joyhub_c_product_page_get(self, **kwargs):
|
||||||
|
"""
|
||||||
|
获得产品分页业务关键字
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info("获得产品分页")
|
||||||
|
resp = self.kw_in_joyhub_c_product_page_get(**kwargs)
|
||||||
|
obj_log.info(f"获得产品分页响应: {resp}")
|
||||||
|
return resp
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
JoyHub C端支付页产品推荐业务关键字层
|
||||||
|
"""
|
||||||
|
import allure
|
||||||
|
from dulizhan.library.BusinessKw.JoyHubC.LoginManage import JoyHubCLoginManage
|
||||||
|
from base_framework.public_tools import log
|
||||||
|
|
||||||
|
obj_log = log.get_logger()
|
||||||
|
|
||||||
|
|
||||||
|
class JoyHubCProductPaymentRecommendManage(JoyHubCLoginManage):
|
||||||
|
"""JoyHub C端支付页产品推荐业务关键字类"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
@allure.step("获得支付页产品推荐分页")
|
||||||
|
def kw_joyhub_c_product_payment_recommend_page_get(self, **kwargs):
|
||||||
|
"""
|
||||||
|
获得支付页产品推荐分页业务关键字
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info("获得支付页产品推荐分页")
|
||||||
|
resp = self.kw_in_joyhub_c_product_payment_recommend_page_get(**kwargs)
|
||||||
|
obj_log.info(f"获得支付页产品推荐分页响应: {resp}")
|
||||||
|
return resp
|
||||||
27
dulizhan/library/BusinessKw/JoyHubC/UserManage.py
Normal file
27
dulizhan/library/BusinessKw/JoyHubC/UserManage.py
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
JoyHub C端用户业务关键字层
|
||||||
|
"""
|
||||||
|
import allure
|
||||||
|
from dulizhan.library.BusinessKw.JoyHubC.LoginManage import JoyHubCLoginManage
|
||||||
|
from base_framework.public_tools import log
|
||||||
|
|
||||||
|
obj_log = log.get_logger()
|
||||||
|
|
||||||
|
|
||||||
|
class JoyHubCUserManage(JoyHubCLoginManage):
|
||||||
|
"""JoyHub C端用户业务关键字类"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
@allure.step("查询当前用户积分")
|
||||||
|
def kw_joyhub_c_client_get_point_get(self):
|
||||||
|
"""
|
||||||
|
查询当前用户积分业务关键字
|
||||||
|
:return: 响应结果
|
||||||
|
"""
|
||||||
|
obj_log.info("查询当前用户积分")
|
||||||
|
resp = self.kw_in_joyhub_c_client_get_point_get()
|
||||||
|
obj_log.info(f"查询当前用户积分响应: {resp}")
|
||||||
|
return resp
|
||||||
1
dulizhan/library/BusinessKw/JoyHubC/__init__.py
Normal file
1
dulizhan/library/BusinessKw/JoyHubC/__init__.py
Normal file
@@ -0,0 +1 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
# -*- coding:utf-8 -*-
|
|
||||||
"""
|
|
||||||
Author: qiaoxinjiu
|
|
||||||
Email: qiaoxinjiu@sparkedu.com
|
|
||||||
Create Date: 2026/01/22 5:58 下午
|
|
||||||
"""
|
|
||||||
import logging
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
# 添加项目根目录到 Python 路径,以便导入 base_framework 模块
|
|
||||||
current_file_path = os.path.abspath(__file__)
|
|
||||||
project_root = os.path.abspath(os.path.join(os.path.dirname(current_file_path), '../../../../'))
|
|
||||||
if project_root not in sys.path:
|
|
||||||
sys.path.insert(0, project_root)
|
|
||||||
|
|
||||||
from base_framework.public_tools import log
|
|
||||||
from base_framework.public_tools.my_faker import MyFaker
|
|
||||||
from base_framework.public_tools.runner import Runner
|
|
||||||
from base_framework.public_tools.pgsqlhelper import PgSqlHelper
|
|
||||||
from base_framework.public_tools import read_config
|
|
||||||
from base_framework.public_tools import utils
|
|
||||||
from base_framework.public_tools import mg_keyword
|
|
||||||
from zhyy.library.ZZYY_interface import ZhyyInterface
|
|
||||||
|
|
||||||
obj_get_log = log.get_logger()
|
|
||||||
obj_my_faker = MyFaker()
|
|
||||||
obj_runner = Runner()
|
|
||||||
obj_pgsql_helper = PgSqlHelper()
|
|
||||||
obj_get_way = utils.Tools()
|
|
||||||
obj_mg_keyword = mg_keyword.ManageKeyWord()
|
|
||||||
|
|
||||||
|
|
||||||
class PurchaseOrder(ZhyyInterface):
|
|
||||||
def __init__(self):
|
|
||||||
'''
|
|
||||||
这个是针对于读取配置文件的初始化函数,用于读取默认参数
|
|
||||||
'''
|
|
||||||
super().__init__()
|
|
||||||
self.config_index_path = os.path.dirname(os.path.abspath(__file__))
|
|
||||||
self.config_index_filePath = os.path.join(self.config_index_path, "purchase.ini")
|
|
||||||
self.config_index_content = read_config.ReadConfig(filename=self.config_index_filePath)
|
|
||||||
|
|
||||||
def kw_zhyy_get_purchase_page_post(self, note, user, **kwargs):
|
|
||||||
"""
|
|
||||||
| 功能说明: | 返回采购工作台采购单列表数据 |
|
|
||||||
| 输入参数: | note | 注释 |
|
|
||||||
|user | 用户信息,传入 'purchase' 默认读取配置文件里面 'purchase' 对应的默认账号信息|
|
|
||||||
|supplier_company_ids | 供应商id | 非必填
|
|
||||||
|payment_status | 付款状态 | 非必填
|
|
||||||
|status | 采购单状态 | 非必填
|
|
||||||
|order_sn | 采购单号 | 非必填
|
|
||||||
|page_no | 页码 | 必填
|
|
||||||
|page_size | 每页条数 | 必填
|
|
||||||
| 返回参数: | {"success":true,"message":"success","code":200,"data":
|
|
||||||
{'todoTask':['PO260116003','PO260115010'],'inProcessTask':['PO260116003','PO260115010']}} | |
|
|
||||||
| 作者信息: | 谯新久 | 修改时间 | 2022-8-20 |
|
|
||||||
"""
|
|
||||||
logging.info("==========={0}===========".format(note))
|
|
||||||
# 获取所有参数
|
|
||||||
supplier_company_ids = kwargs.get("supplier_company_ids")
|
|
||||||
payment_status = kwargs.get("payment_status")
|
|
||||||
status = kwargs.get("status")
|
|
||||||
order_sn = kwargs.get("order_sn")
|
|
||||||
page_no = kwargs.get("page_no")
|
|
||||||
page_size = kwargs.get("page_size")
|
|
||||||
|
|
||||||
# 检查必填参数
|
|
||||||
if not page_no or not page_size:
|
|
||||||
raise Exception("页码和每页条数不能为空")
|
|
||||||
|
|
||||||
# 组装参数字典,只包含非空字段,参数名使用 pageNo 和 pageSize
|
|
||||||
request_params = {
|
|
||||||
"pageNo": page_no,
|
|
||||||
"pageSize": page_size
|
|
||||||
}
|
|
||||||
|
|
||||||
# 如果字段不为空,才添加到参数字典中
|
|
||||||
if supplier_company_ids is not None and supplier_company_ids != "":
|
|
||||||
request_params["supplier_company_ids"] = supplier_company_ids
|
|
||||||
if payment_status is not None and payment_status != "":
|
|
||||||
request_params["payment_status"] = payment_status
|
|
||||||
if status is not None and status != "":
|
|
||||||
request_params["status"] = status
|
|
||||||
if order_sn is not None and order_sn != "":
|
|
||||||
request_params["order_sn"] = order_sn
|
|
||||||
|
|
||||||
# 使用 ** 方式解包字典传递参数
|
|
||||||
get_todo_info = self.kw_in_zhyy_purchase_order_page_post(user=user, **request_params)
|
|
||||||
print(get_todo_info if get_todo_info else "查询失败")
|
|
||||||
return get_todo_info
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
test = PurchaseOrder()
|
|
||||||
a = test.kw_zhyy_get_purchase_page_post(user='purchase', note="测试", page_no=1, page_size=10)
|
|
||||||
print(a)
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
# -*- coding:utf-8 -*-
|
|
||||||
"""
|
|
||||||
Author: qiaoxinjiu
|
|
||||||
Email: qiaoxinjiu@sparkedu.com
|
|
||||||
Create Date: 2022/08/20 5:58 下午
|
|
||||||
"""
|
|
||||||
import logging
|
|
||||||
import os
|
|
||||||
import sys
|
|
||||||
|
|
||||||
# 添加项目根目录到 Python 路径,以便导入 base_framework 模块
|
|
||||||
current_file_path = os.path.abspath(__file__)
|
|
||||||
project_root = os.path.abspath(os.path.join(os.path.dirname(current_file_path), '../../../../'))
|
|
||||||
if project_root not in sys.path:
|
|
||||||
sys.path.insert(0, project_root)
|
|
||||||
|
|
||||||
from base_framework.public_tools import log
|
|
||||||
from base_framework.public_tools.my_faker import MyFaker
|
|
||||||
from base_framework.public_tools.runner import Runner
|
|
||||||
from base_framework.public_tools.pgsqlhelper import PgSqlHelper
|
|
||||||
from base_framework.public_tools import read_config
|
|
||||||
from base_framework.public_tools import utils
|
|
||||||
from base_framework.public_tools import mg_keyword
|
|
||||||
from zhyy.library.ZZYY_interface import ZhyyInterface
|
|
||||||
|
|
||||||
obj_get_log = log.get_logger()
|
|
||||||
obj_my_faker = MyFaker()
|
|
||||||
obj_runner = Runner()
|
|
||||||
obj_pgsql_helper = PgSqlHelper()
|
|
||||||
obj_get_way = utils.Tools()
|
|
||||||
obj_mg_keyword = mg_keyword.ManageKeyWord()
|
|
||||||
|
|
||||||
|
|
||||||
class PurchaseIndex(ZhyyInterface):
|
|
||||||
def __init__(self):
|
|
||||||
'''
|
|
||||||
这个是针对于读取配置文件的初始化函数,用于读取默认参数
|
|
||||||
'''
|
|
||||||
super().__init__()
|
|
||||||
self.config_index_path = os.path.dirname(os.path.abspath(__file__))
|
|
||||||
self.config_index_filePath = os.path.join(self.config_index_path, "purchase.ini")
|
|
||||||
self.config_index_content = read_config.ReadConfig(filename=self.config_index_filePath)
|
|
||||||
|
|
||||||
def kw_zhyy_get_todo(self, note, user):
|
|
||||||
"""
|
|
||||||
| 功能说明: | 返回采购工作台首页待办任务的PO与在办任务PO |
|
|
||||||
| 输入参数: | note | 注释 |
|
|
||||||
|user | 用户信息,传入 'purchase' 默认读取配置文件里面 'purchase' 对应的默认账号信息|
|
|
||||||
| 返回参数: | {"success":true,"message":"success","code":200,"data":
|
|
||||||
{'todoTask':['PO260116003','PO260115010'],'inProcessTask':['PO260116003','PO260115010']}} | |
|
|
||||||
| 作者信息: | 谯新久 | 修改时间 | 2022-8-20 |
|
|
||||||
"""
|
|
||||||
logging.info("==========={0}===========".format(note))
|
|
||||||
get_todo_info = self.kw_in_zhyy_purchase_todo_get(user=user)
|
|
||||||
if get_todo_info['code'] != 0:
|
|
||||||
raise Exception("查询采购待办任务失败: {}".format(get_todo_info))
|
|
||||||
get_todo_info["message"] = "查询采购待办任务成功"
|
|
||||||
data = get_todo_info.get("data")
|
|
||||||
if data is None:
|
|
||||||
raise Exception("返回数据为空,data字段不存在")
|
|
||||||
list_get_todo_task = data.get("todoTask") or []
|
|
||||||
list_get_process_task = data.get("inProcessTask") or []
|
|
||||||
list_todo_task_po = []
|
|
||||||
list_process_task_po = []
|
|
||||||
for todoTask in list_get_todo_task:
|
|
||||||
if isinstance(todoTask, dict):
|
|
||||||
list_todo_task_po.append(todoTask.get("businessSn"))
|
|
||||||
for processTask in list_get_process_task:
|
|
||||||
if isinstance(processTask, dict):
|
|
||||||
list_process_task_po.append(processTask.get("businessSn"))
|
|
||||||
get_todo_info["data"]["todoTask"] = list_todo_task_po
|
|
||||||
get_todo_info["data"]["inProcessTask"] = list_process_task_po
|
|
||||||
if list_todo_task_po:
|
|
||||||
test_purchase = list_todo_task_po[0]
|
|
||||||
# 表在public schema中,使用public.erp_purchase_order格式
|
|
||||||
sql = "SELECT * FROM public.erp_purchase_order WHERE order_sn = '{}'".format(test_purchase)
|
|
||||||
try:
|
|
||||||
obj_pgsql_helper.select_one(sql)
|
|
||||||
except Exception as e:
|
|
||||||
# 如果查询失败,记录日志但不影响主流程
|
|
||||||
obj_get_log.warning("查询采购订单表失败,订单号:{},错误:{}".format(test_purchase, str(e)))
|
|
||||||
return get_todo_info
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
test = PurchaseIndex()
|
|
||||||
a = test.kw_zhyy_get_todo(user='purchase',note="测试")
|
|
||||||
print(a)
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
[qa-user]
|
|
||||||
user_info ={"studentId":21797349,"sex":0,"nickName":"auto st test","birthday":1640966400000,"avatar":"https://stalegacy.huohua.cn/image/huohua/avatar/default/default_avatar1.png"}
|
|
||||||
@@ -14,6 +14,10 @@ from base_framework.public_tools import utils
|
|||||||
from base_framework.public_tools.pgsqlhelper import PgSqlHelper
|
from base_framework.public_tools.pgsqlhelper import PgSqlHelper
|
||||||
import requests
|
import requests
|
||||||
import json
|
import json
|
||||||
|
import re
|
||||||
|
import imaplib
|
||||||
|
import email as email_parser
|
||||||
|
from email.header import decode_header
|
||||||
|
|
||||||
obj_log = log.get_logger()
|
obj_log = log.get_logger()
|
||||||
obj_runner = Runner()
|
obj_runner = Runner()
|
||||||
@@ -25,7 +29,11 @@ class DlzhanInterface:
|
|||||||
self.domain_url = eureka.get_url_from_config()
|
self.domain_url = eureka.get_url_from_config()
|
||||||
self.pg_db = PgSqlHelper()
|
self.pg_db = PgSqlHelper()
|
||||||
self.joyhub_domain = "https://joyhub-website-manager-api-test.best-envision.com"
|
self.joyhub_domain = "https://joyhub-website-manager-api-test.best-envision.com"
|
||||||
|
self.joyhub_c_domain = "https://joyhub-website-frontend-test.best-envision.com"
|
||||||
|
self.joyhub_c_frontend_url = "https://joyhub-website-frontend-test.best-envision.com/"
|
||||||
|
self.joyhub_c_session = requests.session()
|
||||||
self.token = None
|
self.token = None
|
||||||
|
self.joyhub_c_token = None
|
||||||
|
|
||||||
def _get_joyhub_headers(self):
|
def _get_joyhub_headers(self):
|
||||||
headers = {
|
headers = {
|
||||||
@@ -39,6 +47,47 @@ class DlzhanInterface:
|
|||||||
def set_joyhub_token(self, token):
|
def set_joyhub_token(self, token):
|
||||||
self.token = token
|
self.token = token
|
||||||
|
|
||||||
|
def set_joyhub_c_token(self, token):
|
||||||
|
self.joyhub_c_token = token
|
||||||
|
|
||||||
|
def _get_joyhub_c_headers(self):
|
||||||
|
headers = {
|
||||||
|
'accept': '*/*',
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
'jh-appchannel': '5',
|
||||||
|
'origin': self.joyhub_c_domain,
|
||||||
|
'referer': self.joyhub_c_frontend_url,
|
||||||
|
'tenant-id': '126'
|
||||||
|
}
|
||||||
|
if self.joyhub_c_token:
|
||||||
|
headers['Authorization'] = 'Bearer ' + self.joyhub_c_token
|
||||||
|
return headers
|
||||||
|
|
||||||
|
def _joyhub_c_request(self, method, path, is_check='', note='', return_json=True, **kwargs):
|
||||||
|
url = path if path.startswith('http') else "{}{}".format(self.joyhub_c_domain, path)
|
||||||
|
headers = self._get_joyhub_c_headers()
|
||||||
|
obj_log.info("=========== {} ===========".format(note or path))
|
||||||
|
|
||||||
|
req_params = {}
|
||||||
|
for key, value in kwargs.items():
|
||||||
|
if value is not None and value != '':
|
||||||
|
req_params[key] = value
|
||||||
|
|
||||||
|
req_map = {
|
||||||
|
'GET': lambda: self.joyhub_c_session.get(url, headers=headers, params=req_params, verify=False),
|
||||||
|
'POST': lambda: self.joyhub_c_session.post(url, headers=headers, json=req_params, verify=False),
|
||||||
|
'PUT': lambda: self.joyhub_c_session.put(url, headers=headers, json=req_params, verify=False),
|
||||||
|
'DELETE': lambda: self.joyhub_c_session.delete(url, headers=headers, verify=False)
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = req_map.get(method.upper(), lambda: None)()
|
||||||
|
self._check_resp(is_check, resp)
|
||||||
|
|
||||||
|
if return_json:
|
||||||
|
return resp.json()
|
||||||
|
else:
|
||||||
|
return resp
|
||||||
|
|
||||||
def _joyhub_request(self, method, path, is_check='', note='', return_json=True, **kwargs):
|
def _joyhub_request(self, method, path, is_check='', note='', return_json=True, **kwargs):
|
||||||
url = "{}{}".format(self.joyhub_domain, path)
|
url = "{}{}".format(self.joyhub_domain, path)
|
||||||
headers = self._get_joyhub_headers()
|
headers = self._get_joyhub_headers()
|
||||||
@@ -386,8 +435,463 @@ class DlzhanInterface:
|
|||||||
def kw_in_joyhub_agreement_update_put(self, is_check='', **kwargs):
|
def kw_in_joyhub_agreement_update_put(self, is_check='', **kwargs):
|
||||||
return self._joyhub_request('PUT', '/admin-api/jh/agreement/update', is_check, '更新协议', **kwargs)
|
return self._joyhub_request('PUT', '/admin-api/jh/agreement/update', is_check, '更新协议', **kwargs)
|
||||||
|
|
||||||
|
# ============ 售后政策管理接口 ============
|
||||||
|
def kw_in_joyhub_after_sales_policy_create_post(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('POST', '/admin-api/jh/after-sales-policy/create', is_check, '创建售后政策', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_after_sales_policy_delete_delete(self, policy_id, is_check=''):
|
||||||
|
return self._joyhub_request('DELETE', f'/admin-api/jh/after-sales-policy/delete?id={policy_id}', is_check, '删除售后政策')
|
||||||
|
|
||||||
|
def kw_in_joyhub_after_sales_policy_delete_list_delete(self, ids, is_check=''):
|
||||||
|
ids_str = ','.join(map(str, ids))
|
||||||
|
return self._joyhub_request('DELETE', f'/admin-api/jh/after-sales-policy/delete-list?ids={ids_str}', is_check, '批量删除售后政策')
|
||||||
|
|
||||||
|
def kw_in_joyhub_after_sales_policy_get_get(self, policy_id, is_check=''):
|
||||||
|
return self._joyhub_request('GET', f'/admin-api/jh/after-sales-policy/get?id={policy_id}', is_check, '获得售后政策')
|
||||||
|
|
||||||
|
def kw_in_joyhub_after_sales_policy_page_get(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('GET', '/admin-api/jh/after-sales-policy/page', is_check, '获得售后政策分页', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_after_sales_policy_update_put(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('PUT', '/admin-api/jh/after-sales-policy/update', is_check, '更新售后政策', **kwargs)
|
||||||
|
|
||||||
|
# ============ 售后政策-品牌管理接口 ============
|
||||||
|
def kw_in_joyhub_after_sales_brand_create_post(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('POST', '/admin-api/jh/after-sales-brand/create', is_check, '创建售后政策-品牌', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_after_sales_brand_delete_delete(self, brand_id, is_check=''):
|
||||||
|
return self._joyhub_request('DELETE', f'/admin-api/jh/after-sales-brand/delete?id={brand_id}', is_check, '删除售后政策-品牌')
|
||||||
|
|
||||||
|
def kw_in_joyhub_after_sales_brand_delete_list_delete(self, ids, is_check=''):
|
||||||
|
ids_str = ','.join(map(str, ids))
|
||||||
|
return self._joyhub_request('DELETE', f'/admin-api/jh/after-sales-brand/delete-list?ids={ids_str}', is_check, '批量删除售后政策-品牌')
|
||||||
|
|
||||||
|
def kw_in_joyhub_after_sales_brand_get_get(self, brand_id, is_check=''):
|
||||||
|
return self._joyhub_request('GET', f'/admin-api/jh/after-sales-brand/get?id={brand_id}', is_check, '获得售后政策-品牌')
|
||||||
|
|
||||||
|
def kw_in_joyhub_after_sales_brand_list_available_get(self, is_check=''):
|
||||||
|
return self._joyhub_request('GET', '/admin-api/jh/after-sales-brand/list-available', is_check, '获得可用的品牌列表')
|
||||||
|
|
||||||
|
def kw_in_joyhub_after_sales_brand_page_get(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('GET', '/admin-api/jh/after-sales-brand/page', is_check, '获得售后政策-品牌分页', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_after_sales_brand_update_put(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('PUT', '/admin-api/jh/after-sales-brand/update', is_check, '更新售后政策-品牌', **kwargs)
|
||||||
|
|
||||||
|
# ============ 国家信息管理接口 ============
|
||||||
|
def kw_in_joyhub_address_country_create_post(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('POST', '/admin-api/jh/address-country/create', is_check, '创建国家信息', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_address_country_delete_delete(self, country_id, is_check=''):
|
||||||
|
return self._joyhub_request('DELETE', f'/admin-api/jh/address-country/delete?id={country_id}', is_check, '删除国家信息')
|
||||||
|
|
||||||
|
def kw_in_joyhub_address_country_delete_list_delete(self, ids, is_check=''):
|
||||||
|
ids_str = ','.join(map(str, ids))
|
||||||
|
return self._joyhub_request('DELETE', f'/admin-api/jh/address-country/delete-list?ids={ids_str}', is_check, '批量删除国家信息')
|
||||||
|
|
||||||
|
def kw_in_joyhub_address_country_get_get(self, country_id, is_check=''):
|
||||||
|
return self._joyhub_request('GET', f'/admin-api/jh/address-country/get?id={country_id}', is_check, '获得国家信息')
|
||||||
|
|
||||||
|
def kw_in_joyhub_address_country_page_get(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('GET', '/admin-api/jh/address-country/page', is_check, '获得国家信息分页', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_address_country_update_put(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('PUT', '/admin-api/jh/address-country/update', is_check, '更新国家信息', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_address_country_update_status_list_put(self, ids, status, is_check=''):
|
||||||
|
return self._joyhub_request('PUT', f'/admin-api/jh/address-country/update-status-list?ids={ids}&status={status}', is_check, '批量更新国家信息状态')
|
||||||
|
|
||||||
|
# ============ blog分类管理接口 ============
|
||||||
|
def kw_in_joyhub_blog_cate_create_post(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('POST', '/admin-api/jh/blog-cate/create', is_check, '创建blog分类', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_blog_cate_delete_delete(self, cate_id, is_check=''):
|
||||||
|
return self._joyhub_request('DELETE', f'/admin-api/jh/blog-cate/delete?id={cate_id}', is_check, '删除blog分类')
|
||||||
|
|
||||||
|
def kw_in_joyhub_blog_cate_get_get(self, cate_id, is_check=''):
|
||||||
|
return self._joyhub_request('GET', f'/admin-api/jh/blog-cate/get?id={cate_id}', is_check, '获得blog分类')
|
||||||
|
|
||||||
|
def kw_in_joyhub_blog_cate_page_get(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('GET', '/admin-api/jh/blog-cate/page', is_check, '获得blog分类分页', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_blog_cate_update_put(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('PUT', '/admin-api/jh/blog-cate/update', is_check, '更新blog分类', **kwargs)
|
||||||
|
|
||||||
|
# ============ 二维码管理接口 ============
|
||||||
|
def kw_in_joyhub_download_qrcode_create_post(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('POST', '/admin-api/jh/download-qrcode/create', is_check, '创建二维码', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_download_qrcode_get_get(self, qrcode_id, is_check=''):
|
||||||
|
return self._joyhub_request('GET', f'/admin-api/jh/download-qrcode/get?id={qrcode_id}', is_check, '获得二维码')
|
||||||
|
|
||||||
|
def kw_in_joyhub_download_qrcode_page_get(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('GET', '/admin-api/jh/download-qrcode/page', is_check, '获得二维码分页', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_download_qrcode_update_put(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('PUT', '/admin-api/jh/download-qrcode/update', is_check, '更新二维码', **kwargs)
|
||||||
|
|
||||||
|
# ============ FAQ分类管理接口 ============
|
||||||
|
def kw_in_joyhub_faq_cate_create_post(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('POST', '/admin-api/jh/faq-cate/create', is_check, '创建FAQ分类', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_faq_cate_delete_delete(self, faq_cate_id, is_check=''):
|
||||||
|
return self._joyhub_request('DELETE', f'/admin-api/jh/faq-cate/delete?id={faq_cate_id}', is_check, '删除FAQ分类')
|
||||||
|
|
||||||
|
def kw_in_joyhub_faq_cate_get_get(self, faq_cate_id, is_check=''):
|
||||||
|
return self._joyhub_request('GET', f'/admin-api/jh/faq-cate/get?id={faq_cate_id}', is_check, '获得FAQ分类')
|
||||||
|
|
||||||
|
def kw_in_joyhub_faq_cate_list_get(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('GET', '/admin-api/jh/faq-cate/list', is_check, '获得FAQ分类列表', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_faq_cate_update_put(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('PUT', '/admin-api/jh/faq-cate/update', is_check, '更新FAQ分类', **kwargs)
|
||||||
|
|
||||||
|
# ============ FAQ数据管理接口 ============
|
||||||
|
def kw_in_joyhub_faq_cate_list_get(self, is_check=''):
|
||||||
|
return self._joyhub_request('GET', '/admin-api/jh/faq/cate-list', is_check, '获得FAQ分类下拉列表')
|
||||||
|
|
||||||
|
def kw_in_joyhub_faq_create_post(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('POST', '/admin-api/jh/faq/create', is_check, '创建FAQ数据', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_faq_delete_delete(self, faq_id, is_check=''):
|
||||||
|
return self._joyhub_request('DELETE', f'/admin-api/jh/faq/delete?id={faq_id}', is_check, '删除FAQ数据')
|
||||||
|
|
||||||
|
def kw_in_joyhub_faq_delete_list_delete(self, ids, is_check=''):
|
||||||
|
ids_str = ','.join(map(str, ids))
|
||||||
|
return self._joyhub_request('DELETE', f'/admin-api/jh/faq/delete-list?ids={ids_str}', is_check, '批量删除FAQ数据')
|
||||||
|
|
||||||
|
def kw_in_joyhub_faq_get_get(self, faq_id, is_check=''):
|
||||||
|
return self._joyhub_request('GET', f'/admin-api/jh/faq/get?id={faq_id}', is_check, '获得FAQ数据')
|
||||||
|
|
||||||
|
def kw_in_joyhub_faq_page_get(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('GET', '/admin-api/jh/faq/page', is_check, '获得FAQ数据分页', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_faq_update_put(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('PUT', '/admin-api/jh/faq/update', is_check, '更新FAQ数据', **kwargs)
|
||||||
|
|
||||||
|
# ============ news分类管理接口 ============
|
||||||
|
def kw_in_joyhub_news_cate_create_post(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('POST', '/admin-api/jh/news-cate/create', is_check, '创建news分类', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_news_cate_delete_delete(self, news_cate_id, is_check=''):
|
||||||
|
return self._joyhub_request('DELETE', f'/admin-api/jh/news-cate/delete?id={news_cate_id}', is_check, '删除news分类')
|
||||||
|
|
||||||
|
def kw_in_joyhub_news_cate_delete_list_delete(self, ids, is_check=''):
|
||||||
|
ids_str = ','.join(map(str, ids))
|
||||||
|
return self._joyhub_request('DELETE', f'/admin-api/jh/news-cate/delete-list?ids={ids_str}', is_check, '批量删除news分类')
|
||||||
|
|
||||||
|
def kw_in_joyhub_news_cate_get_get(self, news_cate_id, is_check=''):
|
||||||
|
return self._joyhub_request('GET', f'/admin-api/jh/news-cate/get?id={news_cate_id}', is_check, '获得news分类')
|
||||||
|
|
||||||
|
def kw_in_joyhub_news_cate_page_get(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('GET', '/admin-api/jh/news-cate/page', is_check, '获得news分类分页', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_news_cate_update_put(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('PUT', '/admin-api/jh/news-cate/update', is_check, '更新news分类', **kwargs)
|
||||||
|
|
||||||
|
# ============ news管理接口 ============
|
||||||
|
def kw_in_joyhub_news_create_post(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('POST', '/admin-api/jh/news/create', is_check, '创建news管理', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_news_delete_delete(self, news_id, is_check=''):
|
||||||
|
return self._joyhub_request('DELETE', f'/admin-api/jh/news/delete?id={news_id}', is_check, '删除news管理')
|
||||||
|
|
||||||
|
def kw_in_joyhub_news_delete_list_delete(self, ids, is_check=''):
|
||||||
|
ids_str = ','.join(map(str, ids))
|
||||||
|
return self._joyhub_request('DELETE', f'/admin-api/jh/news/delete-list?ids={ids_str}', is_check, '批量删除news管理')
|
||||||
|
|
||||||
|
def kw_in_joyhub_news_get_get(self, news_id, is_check=''):
|
||||||
|
return self._joyhub_request('GET', f'/admin-api/jh/news/get?id={news_id}', is_check, '获得news管理')
|
||||||
|
|
||||||
|
def kw_in_joyhub_news_cate_relation_list_get(self, news_id, is_check=''):
|
||||||
|
return self._joyhub_request('GET', f'/admin-api/jh/news/news-cate-relation/list-by-news-id?newsId={news_id}', is_check, '获得news分类关联列表')
|
||||||
|
|
||||||
|
def kw_in_joyhub_news_page_get(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('GET', '/admin-api/jh/news/page', is_check, '获得news管理分页', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_news_update_put(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('PUT', '/admin-api/jh/news/update', is_check, '更新news管理', **kwargs)
|
||||||
|
|
||||||
|
# ============ 产品分类管理接口 ============
|
||||||
|
def kw_in_joyhub_product_cate_change_status_put(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('PUT', '/admin-api/jh/product-cate/change-status', is_check, '修改产品分类启用/停用状态', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_product_cate_create_post(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('POST', '/admin-api/jh/product-cate/create', is_check, '创建产品分类', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_product_cate_delete_delete(self, product_cate_id, is_check=''):
|
||||||
|
return self._joyhub_request('DELETE', f'/admin-api/jh/product-cate/delete?id={product_cate_id}', is_check, '删除产品分类')
|
||||||
|
|
||||||
|
def kw_in_joyhub_product_cate_delete_list_delete(self, ids, is_check=''):
|
||||||
|
ids_str = ','.join(map(str, ids))
|
||||||
|
return self._joyhub_request('DELETE', f'/admin-api/jh/product-cate/delete-list?ids={ids_str}', is_check, '批量删除产品分类')
|
||||||
|
|
||||||
|
def kw_in_joyhub_product_cate_get_get(self, product_cate_id, is_check=''):
|
||||||
|
return self._joyhub_request('GET', f'/admin-api/jh/product-cate/get?id={product_cate_id}', is_check, '获得产品分类')
|
||||||
|
|
||||||
|
def kw_in_joyhub_product_cate_page_get(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('GET', '/admin-api/jh/product-cate/page', is_check, '获得产品分类分页', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_product_cate_update_put(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('PUT', '/admin-api/jh/product-cate/update', is_check, '更新产品分类', **kwargs)
|
||||||
|
|
||||||
|
# ============ 产品属性管理接口 ============
|
||||||
|
def kw_in_joyhub_product_attr_type_change_status_put(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('PUT', '/admin-api/jh/product-attr-type/change-status', is_check, '启用/停用产品属性状态', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_product_attr_type_create_post(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('POST', '/admin-api/jh/product-attr-type/create', is_check, '创建产品属性', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_product_attr_type_delete_delete(self, product_attr_type_id, is_check=''):
|
||||||
|
return self._joyhub_request('DELETE', f'/admin-api/jh/product-attr-type/delete?id={product_attr_type_id}', is_check, '删除产品属性')
|
||||||
|
|
||||||
|
def kw_in_joyhub_product_attr_type_delete_list_delete(self, ids, is_check=''):
|
||||||
|
ids_str = ','.join(map(str, ids))
|
||||||
|
return self._joyhub_request('DELETE', f'/admin-api/jh/product-attr-type/delete-list?ids={ids_str}', is_check, '批量删除产品属性')
|
||||||
|
|
||||||
|
def kw_in_joyhub_product_attr_type_get_get(self, product_attr_type_id, is_check=''):
|
||||||
|
return self._joyhub_request('GET', f'/admin-api/jh/product-attr-type/get?id={product_attr_type_id}', is_check, '获得产品属性')
|
||||||
|
|
||||||
|
def kw_in_joyhub_product_attr_type_page_get(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('GET', '/admin-api/jh/product-attr-type/page', is_check, '获得产品属性分页', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_product_attr_type_update_put(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('PUT', '/admin-api/jh/product-attr-type/update', is_check, '更新产品属性', **kwargs)
|
||||||
|
|
||||||
|
# ============ 产品属性值管理接口 ============
|
||||||
|
def kw_in_joyhub_product_attr_data_create_post(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('POST', '/admin-api/jh/product-attr-data/create', is_check, '创建产品属性值', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_product_attr_data_delete_delete(self, product_attr_data_id, is_check=''):
|
||||||
|
return self._joyhub_request('DELETE', f'/admin-api/jh/product-attr-data/delete?id={product_attr_data_id}', is_check, '删除产品属性值')
|
||||||
|
|
||||||
|
def kw_in_joyhub_product_attr_data_delete_list_delete(self, ids, is_check=''):
|
||||||
|
ids_str = ','.join(map(str, ids))
|
||||||
|
return self._joyhub_request('DELETE', f'/admin-api/jh/product-attr-data/delete-list?ids={ids_str}', is_check, '批量删除产品属性值')
|
||||||
|
|
||||||
|
def kw_in_joyhub_product_attr_data_get_get(self, product_attr_data_id, is_check=''):
|
||||||
|
return self._joyhub_request('GET', f'/admin-api/jh/product-attr-data/get?id={product_attr_data_id}', is_check, '获得产品属性值')
|
||||||
|
|
||||||
|
def kw_in_joyhub_product_attr_data_page_get(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('GET', '/admin-api/jh/product-attr-data/page', is_check, '获得产品属性值分页', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_product_attr_data_update_put(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('PUT', '/admin-api/jh/product-attr-data/update', is_check, '更新产品属性值', **kwargs)
|
||||||
|
|
||||||
|
# ============ 产品管理接口 ============
|
||||||
|
def kw_in_joyhub_product_change_status_put(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('PUT', '/admin-api/jh/product/change-status', is_check, '批量上下架产品', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_product_create_post(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('POST', '/admin-api/jh/product/create', is_check, '创建产品', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_product_delete_delete(self, product_id, is_check=''):
|
||||||
|
return self._joyhub_request('DELETE', f'/admin-api/jh/product/delete?id={product_id}', is_check, '删除产品')
|
||||||
|
|
||||||
|
def kw_in_joyhub_product_delete_list_delete(self, ids, is_check=''):
|
||||||
|
ids_str = ','.join(map(str, ids))
|
||||||
|
return self._joyhub_request('DELETE', f'/admin-api/jh/product/delete-list?ids={ids_str}', is_check, '批量删除产品')
|
||||||
|
|
||||||
|
def kw_in_joyhub_product_get_get(self, product_id, is_check=''):
|
||||||
|
return self._joyhub_request('GET', f'/admin-api/jh/product/get?id={product_id}', is_check, '获得产品')
|
||||||
|
|
||||||
|
def kw_in_joyhub_product_page_get(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('GET', '/admin-api/jh/product/page', is_check, '获得产品分页', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_product_product_attr_list_by_product_id_get(self, product_id, is_check=''):
|
||||||
|
return self._joyhub_request('GET', f'/admin-api/jh/product/product-attr/list-by-product-id?productId={product_id}', is_check, '获得产品规格类型关联列表')
|
||||||
|
|
||||||
|
def kw_in_joyhub_product_product_detail_list_by_product_id_get(self, product_id, is_check=''):
|
||||||
|
return self._joyhub_request('GET', f'/admin-api/jh/product/product-detail/list-by-product-id?productId={product_id}', is_check, '获得产品详情列表')
|
||||||
|
|
||||||
|
def kw_in_joyhub_product_product_sku_list_by_product_id_get(self, product_id, is_check=''):
|
||||||
|
return self._joyhub_request('GET', f'/admin-api/jh/product/product-sku/list-by-product-id?productId={product_id}', is_check, '获得产品规格列表')
|
||||||
|
|
||||||
|
def kw_in_joyhub_product_product_sku_list_get(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('GET', '/admin-api/jh/product/product/sku-list', is_check, '获得产品及规格列表-优惠券中使用', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_product_update_put(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('PUT', '/admin-api/jh/product/update', is_check, '更新产品', **kwargs)
|
||||||
|
|
||||||
|
# ============ 管理后台-支付页产品推荐接口 ============
|
||||||
|
def kw_in_joyhub_product_payment_recommend_change_rank_num_put(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('PUT', '/admin-api/jh/product-payment-recommend/change-rank-num', is_check, '修改支付页产品推荐排序号', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_product_payment_recommend_change_status_put(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('PUT', '/admin-api/jh/product-payment-recommend/change-status', is_check, '修改支付页产品推荐状态', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_product_payment_recommend_create_post(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('POST', '/admin-api/jh/product-payment-recommend/create', is_check, '创建支付页产品推荐', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_product_payment_recommend_delete_delete(self, recommend_id, is_check=''):
|
||||||
|
return self._joyhub_request('DELETE', f'/admin-api/jh/product-payment-recommend/delete?id={recommend_id}', is_check, '删除支付页产品推荐')
|
||||||
|
|
||||||
|
def kw_in_joyhub_product_payment_recommend_delete_list_delete(self, ids, is_check=''):
|
||||||
|
ids_str = ','.join(map(str, ids))
|
||||||
|
return self._joyhub_request('DELETE', f'/admin-api/jh/product-payment-recommend/delete-list?ids={ids_str}', is_check, '批量删除支付页产品推荐')
|
||||||
|
|
||||||
|
def kw_in_joyhub_product_payment_recommend_page_get(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_request('GET', '/admin-api/jh/product-payment-recommend/page', is_check, '获得支付页产品推荐分页', **kwargs)
|
||||||
|
|
||||||
|
# ============ C端-登录公共接口 ============
|
||||||
|
def kw_in_joyhub_c_login_post(self, path, is_check='', **kwargs):
|
||||||
|
return self._joyhub_c_request('POST', path, is_check, 'JoyHub C端登录', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_c_get_email_code(self, email, code_pattern=r'\d{4,8}'):
|
||||||
|
auth_code = os.environ.get('JOYHUB_C_EMAIL_AUTH_CODE') or os.environ.get('NETEASE_163_AUTH_CODE')
|
||||||
|
if not auth_code:
|
||||||
|
raise Exception("网易163邮箱授权码不能为空,请先设置环境变量 JOYHUB_C_EMAIL_AUTH_CODE")
|
||||||
|
|
||||||
|
obj_log.info("开始连接网易163邮箱获取验证码 - email: {}".format(email))
|
||||||
|
mail = imaplib.IMAP4_SSL('imap.163.com', 993)
|
||||||
|
try:
|
||||||
|
mail.login(email, auth_code)
|
||||||
|
status, _ = mail.select('INBOX')
|
||||||
|
if status != 'OK':
|
||||||
|
raise Exception("邮箱 {} 无法选择收件箱".format(email))
|
||||||
|
status, data = mail.search(None, 'ALL')
|
||||||
|
if status != 'OK' or not data or not data[0]:
|
||||||
|
raise Exception("邮箱 {} 未查询到邮件".format(email))
|
||||||
|
|
||||||
|
email_ids = data[0].split()
|
||||||
|
for email_id in reversed(email_ids[-20:]):
|
||||||
|
status, msg_data = mail.fetch(email_id, '(RFC822)')
|
||||||
|
if status != 'OK' or not msg_data:
|
||||||
|
continue
|
||||||
|
|
||||||
|
msg = email_parser.message_from_bytes(msg_data[0][1])
|
||||||
|
subject = self._decode_email_header(msg.get('Subject', ''))
|
||||||
|
content = self._get_email_content(msg)
|
||||||
|
match = re.search(code_pattern, '{}\n{}'.format(subject, content or ''))
|
||||||
|
if match:
|
||||||
|
obj_log.info("网易163邮箱验证码获取成功")
|
||||||
|
return match.group(0)
|
||||||
|
|
||||||
|
raise Exception("邮箱 {} 最近20封邮件中未匹配到验证码".format(email))
|
||||||
|
finally:
|
||||||
|
try:
|
||||||
|
mail.logout()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def _decode_email_header(self, value):
|
||||||
|
decoded_parts = decode_header(value)
|
||||||
|
result = ''
|
||||||
|
for part, charset in decoded_parts:
|
||||||
|
if isinstance(part, bytes):
|
||||||
|
result += part.decode(charset or 'utf-8', errors='ignore')
|
||||||
|
else:
|
||||||
|
result += part
|
||||||
|
return result
|
||||||
|
|
||||||
|
def _get_email_content(self, msg):
|
||||||
|
contents = []
|
||||||
|
if msg.is_multipart():
|
||||||
|
for part in msg.walk():
|
||||||
|
content_type = part.get_content_type()
|
||||||
|
content_disposition = str(part.get('Content-Disposition'))
|
||||||
|
if content_type in ('text/plain', 'text/html') and 'attachment' not in content_disposition:
|
||||||
|
payload = part.get_payload(decode=True)
|
||||||
|
if payload:
|
||||||
|
charset = part.get_content_charset() or 'utf-8'
|
||||||
|
contents.append(payload.decode(charset, errors='ignore'))
|
||||||
|
else:
|
||||||
|
payload = msg.get_payload(decode=True)
|
||||||
|
if payload:
|
||||||
|
charset = msg.get_content_charset() or 'utf-8'
|
||||||
|
contents.append(payload.decode(charset, errors='ignore'))
|
||||||
|
return '\n'.join(contents)
|
||||||
|
|
||||||
|
# ============ C端-用户接口 ============
|
||||||
|
def kw_in_joyhub_c_client_get_point_get(self, is_check=''):
|
||||||
|
return self._joyhub_c_request('GET', '/web-api/jh/client/get/point', is_check, '查询当前用户积分')
|
||||||
|
|
||||||
|
# ============ C端-Banner信息接口 ============
|
||||||
|
def kw_in_joyhub_c_banner_get_get(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_c_request('GET', '/web-api/jh/banner/get', is_check, '获得Banner管理', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_c_banner_page_get(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_c_request('GET', '/web-api/jh/banner/page', is_check, '获得Banner管理分页', **kwargs)
|
||||||
|
|
||||||
|
# ============ C端-blog信息接口 ============
|
||||||
|
def kw_in_joyhub_c_blog_get_detail_get(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_c_request('GET', '/web-api/jh/blog/get-detail', is_check, '获得blog详情', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_c_blog_get_next_get(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_c_request('GET', '/web-api/jh/blog/get-next', is_check, '获得blog下一条', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_c_blog_page_get(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_c_request('GET', '/web-api/jh/blog/page', is_check, '获得blog管理分页', **kwargs)
|
||||||
|
|
||||||
|
# ============ C端-blog分类接口 ============
|
||||||
|
def kw_in_joyhub_c_blog_cate_list_get(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_c_request('GET', '/web-api/jh/blog-cate/list', is_check, '获得blog分类列表', **kwargs)
|
||||||
|
|
||||||
|
# ============ C端-FAQ接口 ============
|
||||||
|
def kw_in_joyhub_c_faq_cate_list_get(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_c_request('GET', '/web-api/jh/faq/cate-list', is_check, '获得FAQ分类树', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_c_faq_list_get(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_c_request('GET', '/web-api/jh/faq/list', is_check, '获得FAQ列表', **kwargs)
|
||||||
|
|
||||||
|
# ============ C端-news分类接口 ============
|
||||||
|
def kw_in_joyhub_c_news_cate_list_get(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_c_request('GET', '/web-api/jh/news-cate/list', is_check, '获得news分类列表', **kwargs)
|
||||||
|
|
||||||
|
# ============ C端-news管理接口 ============
|
||||||
|
def kw_in_joyhub_c_news_get_detail_get(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_c_request('GET', '/web-api/jh/news/get-detail', is_check, '获得news详情', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_c_news_get_next_get(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_c_request('GET', '/web-api/jh/news/get-next', is_check, '获得news下一条', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_c_news_page_get(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_c_request('GET', '/web-api/jh/news/page', is_check, '获得news管理分页', **kwargs)
|
||||||
|
|
||||||
|
# ============ C端-APP版本接口 ============
|
||||||
|
def kw_in_joyhub_c_web_appversion_page_get(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_c_request('GET', '/web-api/jh/web/appversion/page', is_check, '获取APP版本列表', **kwargs)
|
||||||
|
|
||||||
|
# ============ C端-产品接口 ============
|
||||||
|
def kw_in_joyhub_c_product_get_get(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_c_request('GET', '/web-api/jh/product/get', is_check, '产品详情', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_c_product_page_get(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_c_request('GET', '/web-api/jh/product/page', is_check, '获得产品分页', **kwargs)
|
||||||
|
|
||||||
|
# ============ C端-支付页产品推荐接口 ============
|
||||||
|
def kw_in_joyhub_c_product_payment_recommend_page_get(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_c_request('GET', '/web-api/jh/product-payment-recommend/page', is_check, '获得支付页产品推荐分页', **kwargs)
|
||||||
|
|
||||||
|
# ============ C端-合作联系接口 ============
|
||||||
|
def kw_in_joyhub_c_cooperation_create_post(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_c_request('POST', '/web-api/jh/cooperation/create', is_check, '提交合作联系信息', **kwargs)
|
||||||
|
|
||||||
|
# ============ C端-二维码访问统计接口 ============
|
||||||
|
def kw_in_joyhub_c_download_qrcode_get_get(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_c_request('GET', '/web-api/jh/download-qrcode/get', is_check, '获取二维码信息', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_c_download_qrcode_increment_post(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_c_request('POST', '/web-api/jh/download-qrcode/increment', is_check, '增加二维码访问/点击次数', **kwargs)
|
||||||
|
|
||||||
|
# ============ C端-FAQ联系我们接口 ============
|
||||||
|
def kw_in_joyhub_c_faq_contact_us_create_post(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_c_request('POST', '/web-api/jh/faq-contact-us/create', is_check, '提交FAQ联系信息', **kwargs)
|
||||||
|
|
||||||
|
# ============ C端-点赞记录接口 ============
|
||||||
|
def kw_in_joyhub_c_like_info_create_post(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_c_request('POST', '/web-api/jh/like-info/create', is_check, '创建点赞记录', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_c_like_info_delete_post(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_c_request('POST', '/web-api/jh/like-info/delete', is_check, '取消点赞', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_c_like_info_get_get(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_c_request('GET', '/web-api/jh/like-info/get', is_check, '获得点赞记录', **kwargs)
|
||||||
|
|
||||||
|
def kw_in_joyhub_c_like_info_page_get(self, is_check='', **kwargs):
|
||||||
|
return self._joyhub_c_request('GET', '/web-api/jh/like-info/page', is_check, '获得点赞记录分页', **kwargs)
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
test = DlzhanInterface()
|
test = DlzhanInterface()
|
||||||
a = test.kw_in_zhyy_purchase_todo_get(user="purchase")
|
print()
|
||||||
print(a)
|
|
||||||
|
|||||||
@@ -29,3 +29,12 @@ ${joyhub_test_user_prefix} testuser_ # 测试用户账号前缀
|
|||||||
${joyhub_test_nickname_prefix} 测试用户 # 测试用户昵称前缀
|
${joyhub_test_nickname_prefix} 测试用户 # 测试用户昵称前缀
|
||||||
|
|
||||||
|
|
||||||
|
# ============ JoyHub C端 参数 ============
|
||||||
|
# 登录参数
|
||||||
|
${joyhub_c_login_email} zq464008250@163.com # JoyHub C端登录邮箱
|
||||||
|
${joyhub_c_login_path} https://joyhub-website-frontend-test.best-envision.com/api/web/login/login # JoyHub C端登录接口地址
|
||||||
|
|
||||||
|
# 测试地址
|
||||||
|
${joyhub_c_test_url} https://joyhub-website-frontend-test.best-envision.com/ # JoyHub C端测试地址
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
279
dulizhan/test_case/TestCase/接口/JoyHub/Joyhub_AddressCountry.py
Normal file
279
dulizhan/test_case/TestCase/接口/JoyHub/Joyhub_AddressCountry.py
Normal file
@@ -0,0 +1,279 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
国家信息管理接口测试用例
|
||||||
|
"""
|
||||||
|
import pytest
|
||||||
|
import json
|
||||||
|
import time
|
||||||
|
import logging
|
||||||
|
import allure
|
||||||
|
|
||||||
|
from dulizhan.library.BusinessKw.JoyHub.AddressCountryManage import AddressCountryManage
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("管理后台 - 国家信息管理模块")
|
||||||
|
class TestAddressCountryManage:
|
||||||
|
country_id = None
|
||||||
|
token_set = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setup_class(cls):
|
||||||
|
"""在整个测试类开始时登录一次,所有测试用例共享token"""
|
||||||
|
logging.info("=============================================")
|
||||||
|
logging.info("=========== 开始登录,获取Token ============")
|
||||||
|
logging.info("=============================================")
|
||||||
|
|
||||||
|
cls.test_case = AddressCountryManage()
|
||||||
|
username = "joytest"
|
||||||
|
password = "Zhou1599"
|
||||||
|
|
||||||
|
# 登录逻辑
|
||||||
|
cls.test_case._clear_user_fingerprint(username)
|
||||||
|
|
||||||
|
import requests
|
||||||
|
url = 'https://joyhub-website-manager-api-test.best-envision.com/admin-api/system/auth/login-dev'
|
||||||
|
payload = {'username': username, 'password': password}
|
||||||
|
headers = {'Content-Type': 'application/json', 'tenant-id': '126'}
|
||||||
|
|
||||||
|
response = requests.post(url, json=payload, headers=headers, verify=False, timeout=10)
|
||||||
|
login_response = response.json()
|
||||||
|
|
||||||
|
if login_response and login_response.get('code') == 0:
|
||||||
|
token = login_response.get('data', {}).get('accessToken', '')
|
||||||
|
cls.test_case.set_joyhub_token(token)
|
||||||
|
cls.token_set = True
|
||||||
|
logging.info("登录成功,Token已设置")
|
||||||
|
else:
|
||||||
|
logging.error(f"登录失败: {login_response}")
|
||||||
|
pytest.skip("登录失败,跳过所有测试")
|
||||||
|
|
||||||
|
@allure.story("验证登录")
|
||||||
|
@allure.title("测试登录接口")
|
||||||
|
def test_joyhub_login_post(self):
|
||||||
|
"""测试登录接口"""
|
||||||
|
assert TestAddressCountryManage.token_set is True, "登录失败"
|
||||||
|
logging.info("登录验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证获得国家信息分页")
|
||||||
|
@allure.title("测试获得国家信息分页接口")
|
||||||
|
def test_joyhub_address_country_page_get(self):
|
||||||
|
"""测试获得国家信息分页接口"""
|
||||||
|
with allure.step("1. 调用接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_address_country_page_get(page_num=1, page_size=10)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("2. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert isinstance(resp["data"], dict), "data字段不是字典类型"
|
||||||
|
assert "list" in resp["data"], "响应中缺少list字段"
|
||||||
|
assert isinstance(resp["data"]["list"], list), "list字段不是列表类型"
|
||||||
|
assert "total" in resp["data"], "响应中缺少total字段"
|
||||||
|
assert isinstance(resp["data"]["total"], int), "total字段不是整数类型"
|
||||||
|
logging.info("获得国家信息分页列表验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证创建和更新国家信息")
|
||||||
|
@allure.title("测试创建和更新国家信息接口")
|
||||||
|
def test_joyhub_address_country_create_and_update(self):
|
||||||
|
"""测试创建和更新国家信息接口"""
|
||||||
|
with allure.step("1. 准备创建请求参数"):
|
||||||
|
timestamp = int(time.time())
|
||||||
|
params = {
|
||||||
|
"country_code": f"TC{timestamp}",
|
||||||
|
"country_name": f"测试国家_{timestamp}",
|
||||||
|
"country_name_en": f"Test Country {timestamp}",
|
||||||
|
"phone_code": f"+{timestamp % 1000}",
|
||||||
|
"status": 1
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(params, ensure_ascii=False), name="创建请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用创建接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_address_country_create_post(**params)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="创建响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证创建响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert isinstance(resp["data"], int), "data字段不是整数类型"
|
||||||
|
country_id = resp["data"]
|
||||||
|
TestAddressCountryManage.country_id = country_id
|
||||||
|
logging.info(f"创建国家信息成功,国家信息ID: {country_id}")
|
||||||
|
|
||||||
|
with allure.step("4. 调用更新接口"):
|
||||||
|
update_timestamp = int(time.time())
|
||||||
|
update_params = {
|
||||||
|
"country_id": country_id,
|
||||||
|
"country_code": f"TC{update_timestamp}",
|
||||||
|
"country_name": f"已更新国家_{update_timestamp}",
|
||||||
|
"country_name_en": f"Updated Country {update_timestamp}",
|
||||||
|
"phone_code": f"+{update_timestamp % 1000}",
|
||||||
|
"status": 2
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(update_params, ensure_ascii=False), name="更新请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
update_resp = self.test_case.kw_joyhub_address_country_update_put(**update_params)
|
||||||
|
allure.attach(json.dumps(update_resp, ensure_ascii=False, indent=2), name="更新响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("5. 验证更新响应"):
|
||||||
|
assert update_resp is not None, "响应为空"
|
||||||
|
assert "code" in update_resp, "响应中缺少code字段"
|
||||||
|
assert update_resp["code"] == 0, f"请求失败,code={update_resp.get('code')}"
|
||||||
|
assert "data" in update_resp, "响应中缺少data字段"
|
||||||
|
assert update_resp["data"] is True, "更新国家信息失败"
|
||||||
|
logging.info("更新国家信息验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证获得国家信息详情")
|
||||||
|
@allure.title("测试获得国家信息详情接口")
|
||||||
|
def test_joyhub_address_country_get_get(self):
|
||||||
|
"""测试获得国家信息详情接口"""
|
||||||
|
with allure.step("1. 先创建一个国家信息"):
|
||||||
|
timestamp = int(time.time())
|
||||||
|
create_resp = self.test_case.kw_joyhub_address_country_create_post(
|
||||||
|
country_code=f"TC{timestamp}",
|
||||||
|
country_name=f"详情测试国家_{timestamp}",
|
||||||
|
country_name_en=f"Detail Test Country {timestamp}",
|
||||||
|
phone_code=f"+{timestamp % 1000}",
|
||||||
|
status=2
|
||||||
|
)
|
||||||
|
country_id = create_resp.get("data") if create_resp and create_resp.get("code") == 0 else None
|
||||||
|
|
||||||
|
if not country_id:
|
||||||
|
pytest.skip("创建测试国家信息失败,跳过详情测试")
|
||||||
|
|
||||||
|
allure.attach(json.dumps({"id": country_id}, ensure_ascii=False), name="国家信息ID", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用获得详情接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_address_country_get_get(country_id=country_id)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert isinstance(resp["data"], dict), "data字段不是字典类型"
|
||||||
|
assert "id" in resp["data"], "响应中缺少id字段"
|
||||||
|
assert resp["data"]["id"] == country_id, "返回的ID与请求的不一致"
|
||||||
|
logging.info("获得国家信息详情验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证删除国家信息")
|
||||||
|
@allure.title("测试删除国家信息接口")
|
||||||
|
def test_joyhub_address_country_delete_delete(self):
|
||||||
|
"""测试删除国家信息接口"""
|
||||||
|
with allure.step("1. 先创建一个测试国家信息"):
|
||||||
|
timestamp = int(time.time())
|
||||||
|
create_resp = self.test_case.kw_joyhub_address_country_create_post(
|
||||||
|
country_code=f"TC{timestamp}",
|
||||||
|
country_name=f"待删除国家_{timestamp}",
|
||||||
|
country_name_en=f"Delete Test Country {timestamp}",
|
||||||
|
phone_code=f"+{timestamp % 1000}",
|
||||||
|
status=2
|
||||||
|
)
|
||||||
|
country_id = create_resp.get("data") if create_resp and create_resp.get("code") == 0 else None
|
||||||
|
|
||||||
|
if not country_id:
|
||||||
|
pytest.skip("创建测试国家信息失败,跳过删除测试")
|
||||||
|
|
||||||
|
allure.attach(json.dumps({"id": country_id}, ensure_ascii=False), name="国家信息ID", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用删除接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_address_country_delete_delete(country_id=country_id)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert resp["data"] is True, "删除国家信息失败"
|
||||||
|
logging.info("删除国家信息验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证批量删除国家信息")
|
||||||
|
@allure.title("测试批量删除国家信息接口")
|
||||||
|
def test_joyhub_address_country_delete_list_delete(self):
|
||||||
|
"""测试批量删除国家信息接口"""
|
||||||
|
with allure.step("1. 先创建两个测试国家信息"):
|
||||||
|
timestamp = int(time.time())
|
||||||
|
resp1 = self.test_case.kw_joyhub_address_country_create_post(
|
||||||
|
country_code=f"TC{timestamp}",
|
||||||
|
country_name=f"批量删除国家1_{timestamp}",
|
||||||
|
country_name_en=f"Batch Delete Country 1 {timestamp}",
|
||||||
|
phone_code=f"+{timestamp % 1000}",
|
||||||
|
status=2
|
||||||
|
)
|
||||||
|
resp2 = self.test_case.kw_joyhub_address_country_create_post(
|
||||||
|
country_code=f"TC{timestamp+1}",
|
||||||
|
country_name=f"批量删除国家2_{timestamp}",
|
||||||
|
country_name_en=f"Batch Delete Country 2 {timestamp}",
|
||||||
|
phone_code=f"+{(timestamp+1) % 1000}",
|
||||||
|
status=2
|
||||||
|
)
|
||||||
|
|
||||||
|
country_id1 = resp1.get("data") if resp1 and resp1.get("code") == 0 else None
|
||||||
|
country_id2 = resp2.get("data") if resp2 and resp2.get("code") == 0 else None
|
||||||
|
|
||||||
|
if not country_id1 or not country_id2:
|
||||||
|
pytest.skip("创建测试国家信息失败,跳过批量删除测试")
|
||||||
|
|
||||||
|
country_ids = [country_id1, country_id2]
|
||||||
|
allure.attach(json.dumps({"ids": country_ids}, ensure_ascii=False), name="待删除国家信息IDs", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用批量删除接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_address_country_delete_list_delete(country_ids=country_ids)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert resp["data"] is True, "批量删除国家信息失败"
|
||||||
|
logging.info("批量删除国家信息验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证批量更新国家信息状态")
|
||||||
|
@allure.title("测试批量更新国家信息状态接口")
|
||||||
|
def test_joyhub_address_country_update_status_list_put(self):
|
||||||
|
"""测试批量更新国家信息状态接口"""
|
||||||
|
with allure.step("1. 先创建两个测试国家信息"):
|
||||||
|
timestamp = int(time.time())
|
||||||
|
resp1 = self.test_case.kw_joyhub_address_country_create_post(
|
||||||
|
country_code=f"TC{timestamp}",
|
||||||
|
country_name=f"状态更新国家1_{timestamp}",
|
||||||
|
country_name_en=f"Status Update Country 1 {timestamp}",
|
||||||
|
phone_code=f"+{timestamp % 1000}",
|
||||||
|
status=1
|
||||||
|
)
|
||||||
|
resp2 = self.test_case.kw_joyhub_address_country_create_post(
|
||||||
|
country_code=f"TC{timestamp+1}",
|
||||||
|
country_name=f"状态更新国家2_{timestamp}",
|
||||||
|
country_name_en=f"Status Update Country 2 {timestamp}",
|
||||||
|
phone_code=f"+{(timestamp+1) % 1000}",
|
||||||
|
status=1
|
||||||
|
)
|
||||||
|
|
||||||
|
country_id1 = resp1.get("data") if resp1 and resp1.get("code") == 0 else None
|
||||||
|
country_id2 = resp2.get("data") if resp2 and resp2.get("code") == 0 else None
|
||||||
|
|
||||||
|
if not country_id1 or not country_id2:
|
||||||
|
pytest.skip("创建测试国家信息失败,跳过批量更新状态测试")
|
||||||
|
|
||||||
|
country_ids = [country_id1, country_id2]
|
||||||
|
allure.attach(json.dumps({"ids": country_ids, "status": 2}, ensure_ascii=False), name="批量更新状态参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用批量更新状态接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_address_country_update_status_list_put(country_ids=country_ids, status=2)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert resp["data"] is True, "批量更新国家信息状态失败"
|
||||||
|
logging.info("批量更新国家信息状态验证通过")
|
||||||
552
dulizhan/test_case/TestCase/接口/JoyHub/Joyhub_AfterSalesPolicy.py
Normal file
552
dulizhan/test_case/TestCase/接口/JoyHub/Joyhub_AfterSalesPolicy.py
Normal file
@@ -0,0 +1,552 @@
|
|||||||
|
import pytest
|
||||||
|
import allure
|
||||||
|
import logging
|
||||||
|
import requests
|
||||||
|
import json
|
||||||
|
import time
|
||||||
|
from dulizhan.library.BusinessKw.JoyHub.AfterSalesPolicyManage import AfterSalesPolicyManage
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("管理后台 - 售后政策管理模块")
|
||||||
|
class TestAfterSalesPolicyManage:
|
||||||
|
policy_id = None
|
||||||
|
token_set = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setup_class(cls):
|
||||||
|
"""在整个测试类开始时登录一次,所有测试用例共享token"""
|
||||||
|
logging.info("=============================================")
|
||||||
|
logging.info("=========== 开始登录,获取Token ============")
|
||||||
|
logging.info("=============================================")
|
||||||
|
|
||||||
|
cls.test_case = AfterSalesPolicyManage()
|
||||||
|
username = "joytest"
|
||||||
|
password = "Zhou1599"
|
||||||
|
|
||||||
|
cls.test_case._clear_user_fingerprint(username)
|
||||||
|
|
||||||
|
url = "https://joyhub-website-manager-api-test.best-envision.com/admin-api/system/auth/login-dev"
|
||||||
|
payload = {"username": username, "password": password}
|
||||||
|
headers = {'Content-Type': 'application/json', 'tenant-id': '126'}
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = requests.post(url, json=payload, headers=headers, verify=False, timeout=10)
|
||||||
|
login_response = response.json()
|
||||||
|
|
||||||
|
if login_response and login_response.get('code') == 0:
|
||||||
|
token = login_response.get('data', {}).get('accessToken', '')
|
||||||
|
if token:
|
||||||
|
cls.test_case.set_joyhub_token(token)
|
||||||
|
cls.token_set = True
|
||||||
|
logging.info("登录成功,获取到Token: {}...".format(token[:20]))
|
||||||
|
else:
|
||||||
|
logging.warning("登录成功但未获取到Token")
|
||||||
|
else:
|
||||||
|
logging.error("登录失败: {}".format(login_response))
|
||||||
|
except Exception as e:
|
||||||
|
logging.error("登录异常: {}".format(str(e)))
|
||||||
|
|
||||||
|
@allure.story("验证登录")
|
||||||
|
@allure.title("测试登录接口")
|
||||||
|
def test_joyhub_login_post(self):
|
||||||
|
"""测试登录接口"""
|
||||||
|
assert self.token_set is True, "登录失败,Token未设置"
|
||||||
|
logging.info("登录验证通过,Token已设置")
|
||||||
|
|
||||||
|
@allure.story("验证获得售后政策分页")
|
||||||
|
@allure.title("测试获得售后政策分页接口")
|
||||||
|
def test_joyhub_after_sales_policy_page_get(self):
|
||||||
|
"""测试获得售后政策分页接口"""
|
||||||
|
with allure.step("1. 准备请求参数"):
|
||||||
|
params = {
|
||||||
|
"page_no": 1,
|
||||||
|
"page_size": 10,
|
||||||
|
"title": "",
|
||||||
|
"content": "",
|
||||||
|
"status": ""
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_after_sales_policy_page_get(**params)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert "list" in resp["data"], "响应中缺少list字段"
|
||||||
|
assert "total" in resp["data"], "响应中缺少total字段"
|
||||||
|
assert isinstance(resp["data"]["list"], list), "list字段不是列表类型"
|
||||||
|
assert isinstance(resp["data"]["total"], int), "total字段不是整数类型"
|
||||||
|
logging.info("获得售后政策分页列表验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证创建和更新售后政策")
|
||||||
|
@allure.title("测试创建和更新售后政策接口")
|
||||||
|
def test_joyhub_after_sales_policy_create_and_update(self):
|
||||||
|
"""测试创建和更新售后政策接口"""
|
||||||
|
with allure.step("1. 先创建一个新品牌供售后政策使用"):
|
||||||
|
timestamp = int(time.time())
|
||||||
|
create_brand_resp = self.test_case.kw_joyhub_after_sales_brand_create_post(
|
||||||
|
brand_name=f"测试品牌_售后政策_{timestamp}",
|
||||||
|
after_sales_policy_id=0,
|
||||||
|
status=1
|
||||||
|
)
|
||||||
|
if create_brand_resp and create_brand_resp.get("code") == 0:
|
||||||
|
brand_id = create_brand_resp.get("data")
|
||||||
|
logging.info(f"创建测试品牌成功,品牌ID: {brand_id}")
|
||||||
|
else:
|
||||||
|
pytest.skip(f"创建测试品牌失败: {create_brand_resp}")
|
||||||
|
|
||||||
|
allure.attach(json.dumps({"brand_id": brand_id}, ensure_ascii=False), name="品牌ID", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 准备创建请求参数"):
|
||||||
|
params = {
|
||||||
|
"title": f"测试售后政策_{timestamp}",
|
||||||
|
"content": f"这是测试售后政策内容_{timestamp}",
|
||||||
|
"lang": "de",
|
||||||
|
"brand_id": brand_id,
|
||||||
|
"status": 1
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(params, ensure_ascii=False), name="创建请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("3. 调用创建接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_after_sales_policy_create_post(**params)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="创建响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("4. 验证创建响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert isinstance(resp["data"], int), "data字段不是整数类型"
|
||||||
|
policy_id = resp["data"]
|
||||||
|
TestAfterSalesPolicyManage.policy_id = policy_id
|
||||||
|
logging.info(f"创建售后政策成功,售后政策ID: {policy_id}")
|
||||||
|
|
||||||
|
with allure.step("5. 调用更新接口"):
|
||||||
|
update_timestamp = int(time.time())
|
||||||
|
update_params = {
|
||||||
|
"policy_id": policy_id,
|
||||||
|
"title": f"已更新售后政策_{update_timestamp}",
|
||||||
|
"content": f"已更新售后政策内容_{update_timestamp}",
|
||||||
|
"lang": "ja",
|
||||||
|
"brand_id": brand_id,
|
||||||
|
"status": 2
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(update_params, ensure_ascii=False), name="更新请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
update_resp = self.test_case.kw_joyhub_after_sales_policy_update_put(**update_params)
|
||||||
|
allure.attach(json.dumps(update_resp, ensure_ascii=False, indent=2), name="更新响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("6. 验证更新响应"):
|
||||||
|
assert update_resp is not None, "响应为空"
|
||||||
|
assert "code" in update_resp, "响应中缺少code字段"
|
||||||
|
assert update_resp["code"] == 0, f"请求失败,code={update_resp.get('code')}"
|
||||||
|
assert "data" in update_resp, "响应中缺少data字段"
|
||||||
|
assert update_resp["data"] is True, "更新售后政策失败"
|
||||||
|
logging.info("更新售后政策验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证获得售后政策详情")
|
||||||
|
@allure.title("测试获得售后政策详情接口")
|
||||||
|
def test_joyhub_after_sales_policy_get_get(self):
|
||||||
|
"""测试获得售后政策详情接口"""
|
||||||
|
with allure.step("1. 先创建一个售后政策"):
|
||||||
|
timestamp = int(time.time())
|
||||||
|
create_resp = self.test_case.kw_joyhub_after_sales_policy_create_post(
|
||||||
|
title=f"详情测试售后政策_{timestamp}",
|
||||||
|
content=f"详情测试售后政策内容_{timestamp}",
|
||||||
|
lang="ja",
|
||||||
|
brand_id=12,
|
||||||
|
status=2
|
||||||
|
)
|
||||||
|
policy_id = create_resp.get("data") if create_resp and create_resp.get("code") == 0 else None
|
||||||
|
|
||||||
|
if not policy_id:
|
||||||
|
pytest.skip("创建测试售后政策失败,跳过详情测试")
|
||||||
|
|
||||||
|
allure.attach(json.dumps({"id": policy_id}, ensure_ascii=False), name="售后政策ID", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用获得详情接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_after_sales_policy_get_get(policy_id=policy_id)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert isinstance(resp["data"], dict), "data字段不是字典类型"
|
||||||
|
assert "id" in resp["data"], "响应中缺少id字段"
|
||||||
|
assert resp["data"]["id"] == policy_id, "返回的ID与请求的不一致"
|
||||||
|
logging.info("获得售后政策详情验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证删除售后政策")
|
||||||
|
@allure.title("测试删除售后政策接口")
|
||||||
|
def test_joyhub_after_sales_policy_delete_delete(self):
|
||||||
|
"""测试删除售后政策接口"""
|
||||||
|
with allure.step("1. 先创建一个测试售后政策"):
|
||||||
|
timestamp = int(time.time())
|
||||||
|
create_resp = self.test_case.kw_joyhub_after_sales_policy_create_post(
|
||||||
|
title=f"待删除售后政策_{timestamp}",
|
||||||
|
content=f"待删除售后政策内容_{timestamp}",
|
||||||
|
lang="en",
|
||||||
|
brand_id=12,
|
||||||
|
status=2
|
||||||
|
)
|
||||||
|
policy_id = create_resp.get("data") if create_resp and create_resp.get("code") == 0 else None
|
||||||
|
|
||||||
|
if not policy_id:
|
||||||
|
pytest.skip("创建测试售后政策失败,跳过删除测试")
|
||||||
|
|
||||||
|
allure.attach(json.dumps({"id": policy_id}, ensure_ascii=False), name="待删除售后政策ID", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用删除接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_after_sales_policy_delete_delete(policy_id=policy_id)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert resp["data"] is True, "删除售后政策失败"
|
||||||
|
logging.info("删除售后政策验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证批量删除售后政策")
|
||||||
|
@allure.title("测试批量删除售后政策接口")
|
||||||
|
def test_joyhub_after_sales_policy_delete_list_delete(self):
|
||||||
|
"""测试批量删除售后政策接口"""
|
||||||
|
with allure.step("1. 先创建两个测试售后政策"):
|
||||||
|
timestamp = int(time.time())
|
||||||
|
resp1 = self.test_case.kw_joyhub_after_sales_policy_create_post(
|
||||||
|
title=f"批量删除售后政策1_{timestamp}",
|
||||||
|
content=f"批量删除售后政策内容1_{timestamp}",
|
||||||
|
lang="de",
|
||||||
|
brand_id=12,
|
||||||
|
status=2
|
||||||
|
)
|
||||||
|
resp2 = self.test_case.kw_joyhub_after_sales_policy_create_post(
|
||||||
|
title=f"批量删除售后政策2_{timestamp}",
|
||||||
|
content=f"批量删除售后政策内容2_{timestamp}",
|
||||||
|
lang="ja",
|
||||||
|
brand_id=12,
|
||||||
|
status=2
|
||||||
|
)
|
||||||
|
|
||||||
|
policy_id1 = resp1.get("data") if resp1 and resp1.get("code") == 0 else None
|
||||||
|
policy_id2 = resp2.get("data") if resp2 and resp2.get("code") == 0 else None
|
||||||
|
|
||||||
|
if not policy_id1 or not policy_id2:
|
||||||
|
pytest.skip("创建测试售后政策失败,跳过批量删除测试")
|
||||||
|
|
||||||
|
policy_ids = [policy_id1, policy_id2]
|
||||||
|
allure.attach(json.dumps({"ids": policy_ids}, ensure_ascii=False), name="待删除售后政策IDs", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用批量删除接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_after_sales_policy_delete_list_delete(policy_ids=policy_ids)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert resp["data"] is True, "批量删除售后政策失败"
|
||||||
|
logging.info("批量删除售后政策验证通过")
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("管理后台 - 售后政策-品牌管理模块")
|
||||||
|
class TestAfterSalesBrandManage:
|
||||||
|
brand_id = None
|
||||||
|
policy_id = None
|
||||||
|
token_set = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setup_class(cls):
|
||||||
|
"""在整个测试类开始时登录一次,所有测试用例共享token"""
|
||||||
|
logging.info("=============================================")
|
||||||
|
logging.info("=========== 开始登录,获取Token ============")
|
||||||
|
logging.info("=============================================")
|
||||||
|
|
||||||
|
cls.test_case = AfterSalesPolicyManage()
|
||||||
|
username = "joytest"
|
||||||
|
password = "Zhou1599"
|
||||||
|
|
||||||
|
cls.test_case._clear_user_fingerprint(username)
|
||||||
|
|
||||||
|
url = "https://joyhub-website-manager-api-test.best-envision.com/admin-api/system/auth/login-dev"
|
||||||
|
payload = {"username": username, "password": password}
|
||||||
|
headers = {'Content-Type': 'application/json', 'tenant-id': '126'}
|
||||||
|
|
||||||
|
try:
|
||||||
|
response = requests.post(url, json=payload, headers=headers, verify=False, timeout=10)
|
||||||
|
login_response = response.json()
|
||||||
|
|
||||||
|
if login_response and login_response.get('code') == 0:
|
||||||
|
token = login_response.get('data', {}).get('accessToken', '')
|
||||||
|
if token:
|
||||||
|
cls.test_case.set_joyhub_token(token)
|
||||||
|
cls.token_set = True
|
||||||
|
logging.info("登录成功,获取到Token: {}...".format(token[:20]))
|
||||||
|
else:
|
||||||
|
logging.warning("登录成功但未获取到Token")
|
||||||
|
else:
|
||||||
|
logging.error("登录失败: {}".format(login_response))
|
||||||
|
except Exception as e:
|
||||||
|
logging.error("登录异常: {}".format(str(e)))
|
||||||
|
|
||||||
|
# 创建一个售后政策供品牌测试使用
|
||||||
|
if cls.token_set:
|
||||||
|
timestamp = int(time.time())
|
||||||
|
# 先创建一个新品牌,确保没有活跃的售后政策
|
||||||
|
create_brand_resp = cls.test_case.kw_joyhub_after_sales_brand_create_post(
|
||||||
|
brand_name=f"品牌测试专用_{timestamp}",
|
||||||
|
after_sales_policy_id=0,
|
||||||
|
status=1
|
||||||
|
)
|
||||||
|
if create_brand_resp and create_brand_resp.get("code") == 0:
|
||||||
|
brand_id = create_brand_resp.get("data")
|
||||||
|
logging.info(f"创建测试品牌成功,品牌ID: {brand_id}")
|
||||||
|
|
||||||
|
# 使用新创建的品牌创建售后政策
|
||||||
|
create_resp = cls.test_case.kw_joyhub_after_sales_policy_create_post(
|
||||||
|
title=f"品牌测试售后政策_{timestamp}",
|
||||||
|
content=f"品牌测试售后政策内容_{timestamp}",
|
||||||
|
lang="en",
|
||||||
|
brand_id=brand_id,
|
||||||
|
status=1
|
||||||
|
)
|
||||||
|
if create_resp and create_resp.get("code") == 0:
|
||||||
|
cls.policy_id = create_resp.get("data")
|
||||||
|
logging.info(f"创建测试售后政策成功,ID: {cls.policy_id}")
|
||||||
|
else:
|
||||||
|
logging.warning(f"创建售后政策失败: {create_resp}")
|
||||||
|
else:
|
||||||
|
logging.warning(f"创建测试品牌失败: {create_brand_resp}")
|
||||||
|
|
||||||
|
@allure.story("验证获得售后政策-品牌分页")
|
||||||
|
@allure.title("测试获得售后政策-品牌分页接口")
|
||||||
|
def test_joyhub_after_sales_brand_page_get(self):
|
||||||
|
"""测试获得售后政策-品牌分页接口"""
|
||||||
|
with allure.step("1. 准备请求参数"):
|
||||||
|
params = {
|
||||||
|
"page_no": 1,
|
||||||
|
"page_size": 10,
|
||||||
|
"brand_name": "",
|
||||||
|
"after_sales_policy_id": "",
|
||||||
|
"status": ""
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_after_sales_brand_page_get(**params)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert "list" in resp["data"], "响应中缺少list字段"
|
||||||
|
assert "total" in resp["data"], "响应中缺少total字段"
|
||||||
|
assert isinstance(resp["data"]["list"], list), "list字段不是列表类型"
|
||||||
|
assert isinstance(resp["data"]["total"], int), "total字段不是整数类型"
|
||||||
|
logging.info("获得售后政策-品牌分页列表验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证创建售后政策-品牌")
|
||||||
|
@allure.title("测试创建售后政策-品牌接口")
|
||||||
|
def test_joyhub_after_sales_brand_create_post(self):
|
||||||
|
"""测试创建售后政策-品牌接口"""
|
||||||
|
if not self.policy_id:
|
||||||
|
pytest.skip("未创建测试售后政策,跳过品牌创建测试")
|
||||||
|
|
||||||
|
with allure.step("1. 准备请求参数"):
|
||||||
|
timestamp = int(time.time())
|
||||||
|
params = {
|
||||||
|
"brand_name": f"测试品牌_{timestamp}",
|
||||||
|
"after_sales_policy_id": self.policy_id,
|
||||||
|
"status": 1
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_after_sales_brand_create_post(**params)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert isinstance(resp["data"], int), "data字段不是整数类型"
|
||||||
|
TestAfterSalesBrandManage.brand_id = resp["data"]
|
||||||
|
logging.info(f"创建售后政策-品牌成功,品牌ID: {TestAfterSalesBrandManage.brand_id}")
|
||||||
|
|
||||||
|
@allure.story("验证获得售后政策-品牌详情")
|
||||||
|
@allure.title("测试获得售后政策-品牌详情接口")
|
||||||
|
def test_joyhub_after_sales_brand_get_get(self):
|
||||||
|
"""测试获得售后政策-品牌详情接口"""
|
||||||
|
if not self.policy_id:
|
||||||
|
pytest.skip("未创建测试售后政策,跳过品牌详情测试")
|
||||||
|
|
||||||
|
with allure.step("1. 先创建一个售后政策-品牌"):
|
||||||
|
timestamp = int(time.time())
|
||||||
|
create_resp = self.test_case.kw_joyhub_after_sales_brand_create_post(
|
||||||
|
brand_name=f"详情测试品牌_{timestamp}",
|
||||||
|
after_sales_policy_id=self.policy_id,
|
||||||
|
status=2
|
||||||
|
)
|
||||||
|
brand_id = create_resp.get("data") if create_resp and create_resp.get("code") == 0 else None
|
||||||
|
|
||||||
|
if not brand_id:
|
||||||
|
pytest.skip("创建测试品牌失败,跳过详情测试")
|
||||||
|
|
||||||
|
allure.attach(json.dumps({"id": brand_id}, ensure_ascii=False), name="售后政策-品牌ID", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用获得详情接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_after_sales_brand_get_get(brand_id=brand_id)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert isinstance(resp["data"], dict), "data字段不是字典类型"
|
||||||
|
assert "id" in resp["data"], "响应中缺少id字段"
|
||||||
|
assert resp["data"]["id"] == brand_id, "返回的ID与请求的不一致"
|
||||||
|
logging.info("获得售后政策-品牌详情验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证更新售后政策-品牌")
|
||||||
|
@allure.title("测试更新售后政策-品牌接口")
|
||||||
|
def test_joyhub_after_sales_brand_update_put(self):
|
||||||
|
"""测试更新售后政策-品牌接口"""
|
||||||
|
if not self.policy_id:
|
||||||
|
pytest.skip("未创建测试售后政策,跳过品牌更新测试")
|
||||||
|
|
||||||
|
with allure.step("1. 先创建一个售后政策-品牌"):
|
||||||
|
timestamp = int(time.time())
|
||||||
|
create_resp = self.test_case.kw_joyhub_after_sales_brand_create_post(
|
||||||
|
brand_name=f"待更新品牌_{timestamp}",
|
||||||
|
after_sales_policy_id=self.policy_id,
|
||||||
|
status=1
|
||||||
|
)
|
||||||
|
brand_id = create_resp.get("data") if create_resp and create_resp.get("code") == 0 else None
|
||||||
|
|
||||||
|
if not brand_id:
|
||||||
|
pytest.skip("创建测试品牌失败,跳过更新测试")
|
||||||
|
|
||||||
|
allure.attach(json.dumps({"id": brand_id}, ensure_ascii=False), name="售后政策-品牌ID", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用更新接口"):
|
||||||
|
timestamp = int(time.time())
|
||||||
|
update_params = {
|
||||||
|
"brand_id": brand_id,
|
||||||
|
"brand_name": f"已更新品牌_{timestamp}",
|
||||||
|
"after_sales_policy_id": self.policy_id,
|
||||||
|
"status": 2
|
||||||
|
}
|
||||||
|
resp = self.test_case.kw_joyhub_after_sales_brand_update_put(**update_params)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert resp["data"] is True, "更新售后政策-品牌失败"
|
||||||
|
logging.info("更新售后政策-品牌验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证删除售后政策-品牌")
|
||||||
|
@allure.title("测试删除售后政策-品牌接口")
|
||||||
|
def test_joyhub_after_sales_brand_delete_delete(self):
|
||||||
|
"""测试删除售后政策-品牌接口"""
|
||||||
|
if not self.policy_id:
|
||||||
|
pytest.skip("未创建测试售后政策,跳过品牌删除测试")
|
||||||
|
|
||||||
|
with allure.step("1. 先创建一个测试售后政策-品牌"):
|
||||||
|
timestamp = int(time.time())
|
||||||
|
create_resp = self.test_case.kw_joyhub_after_sales_brand_create_post(
|
||||||
|
brand_name=f"待删除品牌_{timestamp}",
|
||||||
|
after_sales_policy_id=self.policy_id,
|
||||||
|
status=2
|
||||||
|
)
|
||||||
|
brand_id = create_resp.get("data") if create_resp and create_resp.get("code") == 0 else None
|
||||||
|
|
||||||
|
if not brand_id:
|
||||||
|
pytest.skip("创建测试品牌失败,跳过删除测试")
|
||||||
|
|
||||||
|
allure.attach(json.dumps({"id": brand_id}, ensure_ascii=False), name="待删除品牌ID", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用删除接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_after_sales_brand_delete_delete(brand_id=brand_id)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert resp["data"] is True, "删除售后政策-品牌失败"
|
||||||
|
logging.info("删除售后政策-品牌验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证批量删除售后政策-品牌")
|
||||||
|
@allure.title("测试批量删除售后政策-品牌接口")
|
||||||
|
def test_joyhub_after_sales_brand_delete_list_delete(self):
|
||||||
|
"""测试批量删除售后政策-品牌接口"""
|
||||||
|
if not self.policy_id:
|
||||||
|
pytest.skip("未创建测试售后政策,跳过批量删除品牌测试")
|
||||||
|
|
||||||
|
with allure.step("1. 先创建两个测试售后政策-品牌"):
|
||||||
|
timestamp = int(time.time())
|
||||||
|
resp1 = self.test_case.kw_joyhub_after_sales_brand_create_post(
|
||||||
|
brand_name=f"批量删除品牌1_{timestamp}",
|
||||||
|
after_sales_policy_id=self.policy_id,
|
||||||
|
status=2
|
||||||
|
)
|
||||||
|
resp2 = self.test_case.kw_joyhub_after_sales_brand_create_post(
|
||||||
|
brand_name=f"批量删除品牌2_{timestamp}",
|
||||||
|
after_sales_policy_id=self.policy_id,
|
||||||
|
status=2
|
||||||
|
)
|
||||||
|
|
||||||
|
brand_id1 = resp1.get("data") if resp1 and resp1.get("code") == 0 else None
|
||||||
|
brand_id2 = resp2.get("data") if resp2 and resp2.get("code") == 0 else None
|
||||||
|
|
||||||
|
if not brand_id1 or not brand_id2:
|
||||||
|
pytest.skip("创建测试品牌失败,跳过批量删除测试")
|
||||||
|
|
||||||
|
brand_ids = [brand_id1, brand_id2]
|
||||||
|
allure.attach(json.dumps({"ids": brand_ids}, ensure_ascii=False), name="待删除品牌IDs", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用批量删除接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_after_sales_brand_delete_list_delete(brand_ids=brand_ids)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert resp["data"] is True, "批量删除售后政策-品牌失败"
|
||||||
|
logging.info("批量删除售后政策-品牌验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证获得可用的品牌列表")
|
||||||
|
@allure.title("测试获得可用的品牌列表接口")
|
||||||
|
def test_joyhub_after_sales_brand_list_available_get(self):
|
||||||
|
"""测试获得可用的品牌列表接口"""
|
||||||
|
with allure.step("1. 调用接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_after_sales_brand_list_available_get()
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("2. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert isinstance(resp["data"], list), "data字段不是列表类型"
|
||||||
|
logging.info("获得可用的品牌列表验证通过")
|
||||||
200
dulizhan/test_case/TestCase/接口/JoyHub/Joyhub_BlogCate.py
Normal file
200
dulizhan/test_case/TestCase/接口/JoyHub/Joyhub_BlogCate.py
Normal file
@@ -0,0 +1,200 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
blog分类管理接口测试用例
|
||||||
|
"""
|
||||||
|
import pytest
|
||||||
|
import json
|
||||||
|
import time
|
||||||
|
import logging
|
||||||
|
import allure
|
||||||
|
|
||||||
|
from dulizhan.library.BusinessKw.JoyHub.BlogCateManage import BlogCateManage
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("管理后台 - blog分类管理模块")
|
||||||
|
class TestBlogCateManage:
|
||||||
|
cate_id = None
|
||||||
|
token_set = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setup_class(cls):
|
||||||
|
"""在整个测试类开始时登录一次,所有测试用例共享token"""
|
||||||
|
logging.info("=============================================")
|
||||||
|
logging.info("=========== 开始登录,获取Token ============")
|
||||||
|
logging.info("=============================================")
|
||||||
|
|
||||||
|
cls.test_case = BlogCateManage()
|
||||||
|
username = "joytest"
|
||||||
|
password = "Zhou1599"
|
||||||
|
|
||||||
|
cls.test_case._clear_user_fingerprint(username)
|
||||||
|
|
||||||
|
import requests
|
||||||
|
url = 'https://joyhub-website-manager-api-test.best-envision.com/admin-api/system/auth/login-dev'
|
||||||
|
payload = {'username': username, 'password': password}
|
||||||
|
headers = {'Content-Type': 'application/json', 'tenant-id': '126'}
|
||||||
|
|
||||||
|
response = requests.post(url, json=payload, headers=headers, verify=False, timeout=10)
|
||||||
|
login_response = response.json()
|
||||||
|
|
||||||
|
if login_response and login_response.get('code') == 0:
|
||||||
|
token = login_response.get('data', {}).get('accessToken', '')
|
||||||
|
cls.test_case.set_joyhub_token(token)
|
||||||
|
cls.token_set = True
|
||||||
|
logging.info("登录成功,Token已设置")
|
||||||
|
else:
|
||||||
|
logging.error(f"登录失败: {login_response}")
|
||||||
|
pytest.skip("登录失败,跳过所有测试")
|
||||||
|
|
||||||
|
@allure.story("验证登录")
|
||||||
|
@allure.title("测试登录接口")
|
||||||
|
def test_joyhub_login_post(self):
|
||||||
|
"""测试登录接口"""
|
||||||
|
assert TestBlogCateManage.token_set is True, "登录失败"
|
||||||
|
logging.info("登录验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证获得blog分类分页")
|
||||||
|
@allure.title("测试获得blog分类分页接口")
|
||||||
|
def test_joyhub_blog_cate_page_get(self):
|
||||||
|
"""测试获得blog分类分页接口"""
|
||||||
|
with allure.step("1. 调用接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_blog_cate_page_get(page_num=1, page_size=10)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("2. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert isinstance(resp["data"], dict), "data字段不是字典类型"
|
||||||
|
assert "list" in resp["data"], "响应中缺少list字段"
|
||||||
|
assert isinstance(resp["data"]["list"], list), "list字段不是列表类型"
|
||||||
|
assert "total" in resp["data"], "响应中缺少total字段"
|
||||||
|
assert isinstance(resp["data"]["total"], int), "total字段不是整数类型"
|
||||||
|
logging.info("获得blog分类分页列表验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证创建和删除blog分类")
|
||||||
|
@allure.title("测试创建和删除blog分类接口")
|
||||||
|
def test_joyhub_blog_cate_create_and_delete(self):
|
||||||
|
"""测试创建和删除blog分类接口"""
|
||||||
|
with allure.step("1. 准备创建请求参数"):
|
||||||
|
timestamp = int(time.time())
|
||||||
|
params = {
|
||||||
|
"name": f"测试blog分类_{timestamp}",
|
||||||
|
"status": 1,
|
||||||
|
"cover_image": "https://example.com/cover.jpg"
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(params, ensure_ascii=False), name="创建请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用创建接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_blog_cate_create_post(**params)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="创建响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证创建响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert isinstance(resp["data"], int), "data字段不是整数类型"
|
||||||
|
cate_id = resp["data"]
|
||||||
|
TestBlogCateManage.cate_id = cate_id
|
||||||
|
logging.info(f"创建blog分类成功,blog分类ID: {cate_id}")
|
||||||
|
|
||||||
|
with allure.step("4. 调用删除接口"):
|
||||||
|
delete_resp = self.test_case.kw_joyhub_blog_cate_delete_delete(cate_id=cate_id)
|
||||||
|
allure.attach(json.dumps(delete_resp, ensure_ascii=False, indent=2), name="删除响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("5. 验证删除响应"):
|
||||||
|
assert delete_resp is not None, "响应为空"
|
||||||
|
assert "code" in delete_resp, "响应中缺少code字段"
|
||||||
|
assert delete_resp["code"] == 0, f"删除失败,code={delete_resp.get('code')}, msg={delete_resp.get('msg')}"
|
||||||
|
assert "data" in delete_resp, "响应中缺少data字段"
|
||||||
|
assert delete_resp["data"] is True, "删除blog分类失败"
|
||||||
|
logging.info("创建并删除blog分类验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证获得blog分类详情")
|
||||||
|
@allure.title("测试获得blog分类详情接口")
|
||||||
|
def test_joyhub_blog_cate_get_get(self):
|
||||||
|
"""测试获得blog分类详情接口"""
|
||||||
|
with allure.step("1. 从分页获取现有blog分类ID"):
|
||||||
|
page_resp = self.test_case.kw_joyhub_blog_cate_page_get(page_num=1, page_size=10)
|
||||||
|
if not page_resp or page_resp.get("code") != 0:
|
||||||
|
pytest.skip("获取分页失败,跳过详情测试")
|
||||||
|
|
||||||
|
data_list = page_resp.get("data", {}).get("list", [])
|
||||||
|
if not data_list:
|
||||||
|
pytest.skip("暂无blog分类数据,跳过详情测试")
|
||||||
|
|
||||||
|
cate_id = data_list[0].get("id")
|
||||||
|
allure.attach(json.dumps({"id": cate_id}, ensure_ascii=False), name="blog分类ID", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用获得详情接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_blog_cate_get_get(cate_id=cate_id)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert isinstance(resp["data"], dict), "data字段不是字典类型"
|
||||||
|
assert "id" in resp["data"], "响应中缺少id字段"
|
||||||
|
assert resp["data"]["id"] == cate_id, "返回的ID与请求的不一致"
|
||||||
|
logging.info("获得blog分类详情验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证创建和更新blog分类")
|
||||||
|
@allure.title("测试创建和更新blog分类接口")
|
||||||
|
def test_joyhub_blog_cate_create_and_update(self):
|
||||||
|
"""测试创建和更新blog分类接口"""
|
||||||
|
with allure.step("1. 创建blog分类"):
|
||||||
|
timestamp = int(time.time())
|
||||||
|
create_params = {
|
||||||
|
"name": f"测试更新blog分类_{timestamp}",
|
||||||
|
"status": 1,
|
||||||
|
"cover_image": "https://example.com/cover.jpg"
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(create_params, ensure_ascii=False), name="创建请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
create_resp = self.test_case.kw_joyhub_blog_cate_create_post(**create_params)
|
||||||
|
allure.attach(json.dumps(create_resp, ensure_ascii=False, indent=2), name="创建响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
assert create_resp is not None, "响应为空"
|
||||||
|
assert "code" in create_resp, "响应中缺少code字段"
|
||||||
|
assert create_resp["code"] == 0, f"创建失败,code={create_resp.get('code')}, msg={create_resp.get('msg')}"
|
||||||
|
assert "data" in create_resp, "响应中缺少data字段"
|
||||||
|
assert isinstance(create_resp["data"], int), "data字段不是整数类型"
|
||||||
|
cate_id = create_resp["data"]
|
||||||
|
logging.info(f"创建blog分类成功,blog分类ID: {cate_id}")
|
||||||
|
|
||||||
|
with allure.step("2. 调用更新接口"):
|
||||||
|
timestamp = int(time.time())
|
||||||
|
update_params = {
|
||||||
|
"cate_id": cate_id,
|
||||||
|
"name": f"测试更新blog分类_{timestamp}",
|
||||||
|
"status": 1,
|
||||||
|
"cover_image": "https://example.com/cover_updated.jpg"
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(update_params, ensure_ascii=False), name="更新请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
update_resp = self.test_case.kw_joyhub_blog_cate_update_put(**update_params)
|
||||||
|
allure.attach(json.dumps(update_resp, ensure_ascii=False, indent=2), name="更新响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证更新响应"):
|
||||||
|
assert update_resp is not None, "响应为空"
|
||||||
|
assert "code" in update_resp, "响应中缺少code字段"
|
||||||
|
if update_resp["code"] == 500:
|
||||||
|
logging.warning(f"更新接口返回500错误: {update_resp}")
|
||||||
|
pytest.skip("更新接口服务端错误,跳过测试")
|
||||||
|
assert update_resp["code"] == 0, f"更新失败,code={update_resp.get('code')}, msg={update_resp.get('msg')}"
|
||||||
|
assert "data" in update_resp, "响应中缺少data字段"
|
||||||
|
assert update_resp["data"] is True, "更新blog分类失败"
|
||||||
|
logging.info("创建并更新blog分类验证通过")
|
||||||
|
|
||||||
|
with allure.step("4. 清理测试数据"):
|
||||||
|
delete_resp = self.test_case.kw_joyhub_blog_cate_delete_delete(cate_id=cate_id)
|
||||||
|
if delete_resp and delete_resp.get("code") == 0:
|
||||||
|
logging.info("清理测试数据成功")
|
||||||
|
else:
|
||||||
|
logging.warning(f"清理测试数据失败: {delete_resp}")
|
||||||
162
dulizhan/test_case/TestCase/接口/JoyHub/Joyhub_DownloadQrcode.py
Normal file
162
dulizhan/test_case/TestCase/接口/JoyHub/Joyhub_DownloadQrcode.py
Normal file
@@ -0,0 +1,162 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
二维码管理接口测试用例
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import pytest
|
||||||
|
import allure
|
||||||
|
import logging
|
||||||
|
import time
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from dulizhan.library.BusinessKw.JoyHub.DownloadQrcodeManage import DownloadQrcodeManage
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("管理后台 - 二维码管理模块")
|
||||||
|
class TestDownloadQrcodeManage:
|
||||||
|
qrcode_id = None
|
||||||
|
token_set = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setup_class(cls):
|
||||||
|
"""在整个测试类开始时登录一次,所有测试用例共享token"""
|
||||||
|
logging.info("=============================================")
|
||||||
|
logging.info("=========== 开始登录,获取Token ============")
|
||||||
|
logging.info("=============================================")
|
||||||
|
|
||||||
|
cls.test_case = DownloadQrcodeManage()
|
||||||
|
username = "joytest"
|
||||||
|
password = "Zhou1599"
|
||||||
|
|
||||||
|
cls.test_case._clear_user_fingerprint(username)
|
||||||
|
|
||||||
|
url = 'https://joyhub-website-manager-api-test.best-envision.com/admin-api/system/auth/login-dev'
|
||||||
|
payload = {'username': username, 'password': password}
|
||||||
|
headers = {'Content-Type': 'application/json', 'tenant-id': '126'}
|
||||||
|
|
||||||
|
response = requests.post(url, json=payload, headers=headers, verify=False, timeout=10)
|
||||||
|
login_response = response.json()
|
||||||
|
|
||||||
|
if login_response and login_response.get('code') == 0:
|
||||||
|
token = login_response.get('data', {}).get('accessToken', '')
|
||||||
|
cls.test_case.set_joyhub_token(token)
|
||||||
|
cls.token_set = True
|
||||||
|
logging.info("登录成功,Token已设置")
|
||||||
|
else:
|
||||||
|
logging.error(f"登录失败: {login_response}")
|
||||||
|
|
||||||
|
@allure.story("验证登录接口")
|
||||||
|
@allure.title("测试登录接口")
|
||||||
|
def test_joyhub_login_post(self):
|
||||||
|
"""测试登录接口"""
|
||||||
|
assert TestDownloadQrcodeManage.token_set is True, "登录失败,未获取到token"
|
||||||
|
logging.info("登录验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证获得二维码分页列表")
|
||||||
|
@allure.title("测试获得二维码分页列表接口")
|
||||||
|
def test_joyhub_download_qrcode_page_get(self):
|
||||||
|
"""测试获得二维码分页列表接口"""
|
||||||
|
with allure.step("1. 调用分页接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_download_qrcode_page_get(page_no=1, page_size=10)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("2. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert "pageResult" in resp["data"], "响应中缺少pageResult字段"
|
||||||
|
assert "list" in resp["data"]["pageResult"], "响应中缺少list字段"
|
||||||
|
assert isinstance(resp["data"]["pageResult"]["list"], list), "list字段不是列表类型"
|
||||||
|
assert "total" in resp["data"]["pageResult"], "响应中缺少total字段"
|
||||||
|
assert isinstance(resp["data"]["pageResult"]["total"], int), "total字段不是整数类型"
|
||||||
|
logging.info("获得二维码分页列表验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证获得二维码详情")
|
||||||
|
@allure.title("测试获得二维码详情接口")
|
||||||
|
def test_joyhub_download_qrcode_get_get(self):
|
||||||
|
"""测试获得二维码详情接口"""
|
||||||
|
with allure.step("1. 从分页获取现有二维码ID"):
|
||||||
|
page_resp = self.test_case.kw_joyhub_download_qrcode_page_get(page_no=1, page_size=10)
|
||||||
|
assert page_resp.get("code") == 0, f"获取分页失败,code={page_resp.get('code')}, msg={page_resp.get('msg')}"
|
||||||
|
assert page_resp.get("data", {}).get("pageResult", {}).get("list"), "没有找到可用的二维码数据"
|
||||||
|
qrcode_id = page_resp["data"]["pageResult"]["list"][0].get("id")
|
||||||
|
assert qrcode_id, "二维码ID为空"
|
||||||
|
|
||||||
|
with allure.step("2. 调用获取详情接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_download_qrcode_get_get(qrcode_id=qrcode_id)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert "id" in resp["data"], "响应中缺少id字段"
|
||||||
|
assert resp["data"]["id"] == qrcode_id, "返回的ID与请求的ID不一致"
|
||||||
|
assert "title" in resp["data"], "响应中缺少title字段"
|
||||||
|
assert isinstance(resp["data"]["title"], str), "title字段不是字符串类型"
|
||||||
|
logging.info("获得二维码详情验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证创建和更新二维码")
|
||||||
|
@allure.title("测试创建和更新二维码接口")
|
||||||
|
def test_joyhub_download_qrcode_create_and_update(self):
|
||||||
|
"""测试创建和更新二维码接口"""
|
||||||
|
created_title = None
|
||||||
|
|
||||||
|
with allure.step("1. 创建二维码"):
|
||||||
|
timestamp = int(time.time())
|
||||||
|
created_title = f"测试二维码_{timestamp}"
|
||||||
|
create_params = {
|
||||||
|
"title": created_title,
|
||||||
|
"status": 1
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(create_params, ensure_ascii=False), name="创建请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
create_resp = self.test_case.kw_joyhub_download_qrcode_create_post(**create_params)
|
||||||
|
allure.attach(json.dumps(create_resp, ensure_ascii=False, indent=2), name="创建响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
assert create_resp is not None, "响应为空"
|
||||||
|
assert "code" in create_resp, "响应中缺少code字段"
|
||||||
|
assert create_resp["code"] == 0, f"创建失败,code={create_resp.get('code')}, msg={create_resp.get('msg')}"
|
||||||
|
assert "data" in create_resp, "响应中缺少data字段"
|
||||||
|
assert isinstance(create_resp["data"], int), "data字段不是整数类型"
|
||||||
|
qrcode_id = create_resp["data"]
|
||||||
|
TestDownloadQrcodeManage.qrcode_id = qrcode_id
|
||||||
|
logging.info(f"创建二维码成功,ID: {qrcode_id}")
|
||||||
|
|
||||||
|
with allure.step("2. 调用更新接口"):
|
||||||
|
timestamp = int(time.time())
|
||||||
|
update_params = {
|
||||||
|
"qrcode_id": qrcode_id,
|
||||||
|
"title": f"测试二维码_{timestamp}_updated",
|
||||||
|
"status": 2
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(update_params, ensure_ascii=False), name="更新请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
update_resp = self.test_case.kw_joyhub_download_qrcode_update_put(**update_params)
|
||||||
|
allure.attach(json.dumps(update_resp, ensure_ascii=False, indent=2), name="更新响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证更新响应"):
|
||||||
|
assert update_resp is not None, "响应为空"
|
||||||
|
assert "code" in update_resp, "响应中缺少code字段"
|
||||||
|
assert update_resp["code"] == 0, f"更新失败,code={update_resp.get('code')}, msg={update_resp.get('msg')}"
|
||||||
|
assert "data" in update_resp, "响应中缺少data字段"
|
||||||
|
assert update_resp["data"] is True, "更新二维码失败"
|
||||||
|
logging.info("创建并更新二维码验证通过")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def teardown_class(cls):
|
||||||
|
"""在整个测试类结束时清理测试数据"""
|
||||||
|
logging.info("=============================================")
|
||||||
|
logging.info("=========== 清理测试数据 ============")
|
||||||
|
logging.info("=============================================")
|
||||||
|
|
||||||
|
# 从数据库表jh_download_qrcode中删除测试数据
|
||||||
|
if cls.qrcode_id:
|
||||||
|
cls.test_case.clean_test_data_from_db(f"测试二维码_{cls.qrcode_id}")
|
||||||
|
else:
|
||||||
|
# 如果没有获取到qrcode_id,尝试删除所有测试数据
|
||||||
|
cls.test_case.clean_test_data_from_db("测试二维码_")
|
||||||
181
dulizhan/test_case/TestCase/接口/JoyHub/Joyhub_Faq.py
Normal file
181
dulizhan/test_case/TestCase/接口/JoyHub/Joyhub_Faq.py
Normal file
@@ -0,0 +1,181 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
FAQ数据管理接口测试用例
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import pytest
|
||||||
|
import allure
|
||||||
|
import logging
|
||||||
|
import time
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from dulizhan.library.BusinessKw.JoyHub.FaqManage import FaqManage
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("管理后台 - FAQ数据管理模块")
|
||||||
|
class TestFaqManage:
|
||||||
|
faq_id = None
|
||||||
|
faq_cate_id = None
|
||||||
|
token_set = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setup_class(cls):
|
||||||
|
"""在整个测试类开始时登录一次,所有测试用例共享token"""
|
||||||
|
logging.info("=============================================")
|
||||||
|
logging.info("=========== 开始登录,获取Token ============")
|
||||||
|
logging.info("=============================================")
|
||||||
|
|
||||||
|
cls.test_case = FaqManage()
|
||||||
|
username = "joytest"
|
||||||
|
password = "Zhou1599"
|
||||||
|
|
||||||
|
cls.test_case._clear_user_fingerprint(username)
|
||||||
|
|
||||||
|
url = 'https://joyhub-website-manager-api-test.best-envision.com/admin-api/system/auth/login-dev'
|
||||||
|
payload = {'username': username, 'password': password}
|
||||||
|
headers = {'Content-Type': 'application/json', 'tenant-id': '126'}
|
||||||
|
|
||||||
|
response = requests.post(url, json=payload, headers=headers, verify=False, timeout=10)
|
||||||
|
login_response = response.json()
|
||||||
|
|
||||||
|
if login_response and login_response.get('code') == 0:
|
||||||
|
token = login_response.get('data', {}).get('accessToken', '')
|
||||||
|
cls.test_case.set_joyhub_token(token)
|
||||||
|
cls.token_set = True
|
||||||
|
logging.info("登录成功,Token已设置")
|
||||||
|
|
||||||
|
# 获取FAQ分类ID供后续使用
|
||||||
|
cate_list_resp = cls.test_case.kw_joyhub_faq_cate_list_get()
|
||||||
|
if cate_list_resp.get('code') == 0 and cate_list_resp.get('data'):
|
||||||
|
cls.faq_cate_id = cate_list_resp['data'][0].get('faqCateId')
|
||||||
|
logging.info(f"获取到FAQ分类ID: {cls.faq_cate_id}")
|
||||||
|
else:
|
||||||
|
logging.error(f"登录失败: {login_response}")
|
||||||
|
|
||||||
|
@allure.story("验证登录接口")
|
||||||
|
@allure.title("测试登录接口")
|
||||||
|
def test_joyhub_login_post(self):
|
||||||
|
"""测试登录接口"""
|
||||||
|
assert TestFaqManage.token_set is True, "登录失败,未获取到token"
|
||||||
|
logging.info("登录验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证获得FAQ数据分页")
|
||||||
|
@allure.title("测试获得FAQ数据分页接口")
|
||||||
|
def test_joyhub_faq_page_get(self):
|
||||||
|
"""测试获得FAQ数据分页接口"""
|
||||||
|
with allure.step("1. 调用分页接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_faq_page_get(page_no=1, page_size=10)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("2. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert "list" in resp["data"], "响应中缺少list字段"
|
||||||
|
assert isinstance(resp["data"]["list"], list), "list字段不是列表类型"
|
||||||
|
logging.info("获得FAQ数据分页验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证获得FAQ数据详情")
|
||||||
|
@allure.title("测试获得FAQ数据详情接口")
|
||||||
|
def test_joyhub_faq_get_get(self):
|
||||||
|
"""测试获得FAQ数据详情接口"""
|
||||||
|
with allure.step("1. 从分页获取现有FAQ数据ID"):
|
||||||
|
page_resp = self.test_case.kw_joyhub_faq_page_get(page_no=1, page_size=10)
|
||||||
|
assert page_resp.get("code") == 0, f"获取分页失败,code={page_resp.get('code')}, msg={page_resp.get('msg')}"
|
||||||
|
assert page_resp.get("data", {}).get("list"), "没有找到可用的FAQ数据"
|
||||||
|
faq_id = page_resp["data"]["list"][0].get("id")
|
||||||
|
assert faq_id, "FAQ数据ID为空"
|
||||||
|
|
||||||
|
with allure.step("2. 调用获取详情接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_faq_get_get(faq_id=faq_id)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert "id" in resp["data"], "响应中缺少id字段"
|
||||||
|
assert resp["data"]["id"] == faq_id, "返回的ID与请求的ID不一致"
|
||||||
|
assert "question" in resp["data"], "响应中缺少question字段"
|
||||||
|
assert isinstance(resp["data"]["question"], str), "question字段不是字符串类型"
|
||||||
|
logging.info("获得FAQ数据详情验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证创建和更新FAQ数据")
|
||||||
|
@allure.title("测试创建和更新FAQ数据接口")
|
||||||
|
def test_joyhub_faq_create_and_update(self):
|
||||||
|
"""测试创建和更新FAQ数据接口"""
|
||||||
|
if not TestFaqManage.faq_cate_id:
|
||||||
|
pytest.skip("没有可用的FAQ分类,跳过测试")
|
||||||
|
|
||||||
|
with allure.step("1. 创建FAQ数据"):
|
||||||
|
timestamp = int(time.time())
|
||||||
|
create_params = {
|
||||||
|
"faq_cate_id": TestFaqManage.faq_cate_id,
|
||||||
|
"question": f"测试问题_{timestamp}",
|
||||||
|
"answer": f"测试回答内容_{timestamp}",
|
||||||
|
"rank_num": 1,
|
||||||
|
"lang": "zh_CN",
|
||||||
|
"is_hot": 0,
|
||||||
|
"status": 1
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(create_params, ensure_ascii=False), name="创建请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
create_resp = self.test_case.kw_joyhub_faq_create_post(**create_params)
|
||||||
|
allure.attach(json.dumps(create_resp, ensure_ascii=False, indent=2), name="创建响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
assert create_resp is not None, "响应为空"
|
||||||
|
assert "code" in create_resp, "响应中缺少code字段"
|
||||||
|
assert create_resp["code"] == 0, f"创建失败,code={create_resp.get('code')}, msg={create_resp.get('msg')}"
|
||||||
|
assert "data" in create_resp, "响应中缺少data字段"
|
||||||
|
assert isinstance(create_resp["data"], int), "data字段不是整数类型"
|
||||||
|
faq_id = create_resp["data"]
|
||||||
|
TestFaqManage.faq_id = faq_id
|
||||||
|
logging.info(f"创建FAQ数据成功,ID: {faq_id}")
|
||||||
|
|
||||||
|
with allure.step("2. 调用更新接口"):
|
||||||
|
timestamp = int(time.time())
|
||||||
|
update_params = {
|
||||||
|
"faq_id": faq_id,
|
||||||
|
"faq_cate_id": TestFaqManage.faq_cate_id,
|
||||||
|
"question": f"测试问题_{timestamp}_updated",
|
||||||
|
"answer": f"测试回答内容_{timestamp}_updated",
|
||||||
|
"rank_num": 2,
|
||||||
|
"lang": "en",
|
||||||
|
"is_hot": 1,
|
||||||
|
"status": 2
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(update_params, ensure_ascii=False), name="更新请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
update_resp = self.test_case.kw_joyhub_faq_update_put(**update_params)
|
||||||
|
allure.attach(json.dumps(update_resp, ensure_ascii=False, indent=2), name="更新响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证更新响应"):
|
||||||
|
assert update_resp is not None, "响应为空"
|
||||||
|
assert "code" in update_resp, "响应中缺少code字段"
|
||||||
|
assert update_resp["code"] == 0, f"更新失败,code={update_resp.get('code')}, msg={update_resp.get('msg')}"
|
||||||
|
assert "data" in update_resp, "响应中缺少data字段"
|
||||||
|
assert update_resp["data"] is True, "更新FAQ数据失败"
|
||||||
|
logging.info("创建并更新FAQ数据验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证删除FAQ数据")
|
||||||
|
@allure.title("测试删除FAQ数据接口")
|
||||||
|
def test_joyhub_faq_delete_delete(self):
|
||||||
|
"""测试删除FAQ数据接口"""
|
||||||
|
if not TestFaqManage.faq_id:
|
||||||
|
pytest.skip("没有可删除的FAQ数据")
|
||||||
|
|
||||||
|
with allure.step("1. 调用删除接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_faq_delete_delete(faq_id=TestFaqManage.faq_id)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("2. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"删除失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert resp["data"] is True, "删除FAQ数据失败"
|
||||||
|
logging.info("删除FAQ数据验证通过")
|
||||||
166
dulizhan/test_case/TestCase/接口/JoyHub/Joyhub_FaqCate.py
Normal file
166
dulizhan/test_case/TestCase/接口/JoyHub/Joyhub_FaqCate.py
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
FAQ分类管理接口测试用例
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import pytest
|
||||||
|
import allure
|
||||||
|
import logging
|
||||||
|
import time
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from dulizhan.library.BusinessKw.JoyHub.FaqCateManage import FaqCateManage
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("管理后台 - FAQ分类管理模块")
|
||||||
|
class TestFaqCateManage:
|
||||||
|
faq_cate_id = None
|
||||||
|
token_set = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setup_class(cls):
|
||||||
|
"""在整个测试类开始时登录一次,所有测试用例共享token"""
|
||||||
|
logging.info("=============================================")
|
||||||
|
logging.info("=========== 开始登录,获取Token ============")
|
||||||
|
logging.info("=============================================")
|
||||||
|
|
||||||
|
cls.test_case = FaqCateManage()
|
||||||
|
username = "joytest"
|
||||||
|
password = "Zhou1599"
|
||||||
|
|
||||||
|
cls.test_case._clear_user_fingerprint(username)
|
||||||
|
|
||||||
|
url = 'https://joyhub-website-manager-api-test.best-envision.com/admin-api/system/auth/login-dev'
|
||||||
|
payload = {'username': username, 'password': password}
|
||||||
|
headers = {'Content-Type': 'application/json', 'tenant-id': '126'}
|
||||||
|
|
||||||
|
response = requests.post(url, json=payload, headers=headers, verify=False, timeout=10)
|
||||||
|
login_response = response.json()
|
||||||
|
|
||||||
|
if login_response and login_response.get('code') == 0:
|
||||||
|
token = login_response.get('data', {}).get('accessToken', '')
|
||||||
|
cls.test_case.set_joyhub_token(token)
|
||||||
|
cls.token_set = True
|
||||||
|
logging.info("登录成功,Token已设置")
|
||||||
|
else:
|
||||||
|
logging.error(f"登录失败: {login_response}")
|
||||||
|
|
||||||
|
@allure.story("验证登录接口")
|
||||||
|
@allure.title("测试登录接口")
|
||||||
|
def test_joyhub_login_post(self):
|
||||||
|
"""测试登录接口"""
|
||||||
|
assert TestFaqCateManage.token_set is True, "登录失败,未获取到token"
|
||||||
|
logging.info("登录验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证获得FAQ分类列表")
|
||||||
|
@allure.title("测试获得FAQ分类列表接口")
|
||||||
|
def test_joyhub_faq_cate_list_get(self):
|
||||||
|
"""测试获得FAQ分类列表接口"""
|
||||||
|
with allure.step("1. 调用列表接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_faq_cate_list_get()
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("2. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert isinstance(resp["data"], list), "data字段不是列表类型"
|
||||||
|
logging.info("获得FAQ分类列表验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证获得FAQ分类详情")
|
||||||
|
@allure.title("测试获得FAQ分类详情接口")
|
||||||
|
def test_joyhub_faq_cate_get_get(self):
|
||||||
|
"""测试获得FAQ分类详情接口"""
|
||||||
|
with allure.step("1. 从列表获取现有FAQ分类ID"):
|
||||||
|
list_resp = self.test_case.kw_joyhub_faq_cate_list_get()
|
||||||
|
assert list_resp.get("code") == 0, f"获取列表失败,code={list_resp.get('code')}, msg={list_resp.get('msg')}"
|
||||||
|
assert list_resp.get("data"), "没有找到可用的FAQ分类数据"
|
||||||
|
faq_cate_id = list_resp["data"][0].get("id") or list_resp["data"][0].get("faqCateId")
|
||||||
|
assert faq_cate_id, "FAQ分类ID为空"
|
||||||
|
|
||||||
|
with allure.step("2. 调用获取详情接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_faq_cate_get_get(faq_cate_id=faq_cate_id)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert "id" in resp["data"], "响应中缺少id字段"
|
||||||
|
assert resp["data"]["id"] == faq_cate_id, "返回的ID与请求的ID不一致"
|
||||||
|
assert "title" in resp["data"], "响应中缺少title字段"
|
||||||
|
assert isinstance(resp["data"]["title"], str), "title字段不是字符串类型"
|
||||||
|
logging.info("获得FAQ分类详情验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证创建和更新FAQ分类")
|
||||||
|
@allure.title("测试创建和更新FAQ分类接口")
|
||||||
|
def test_joyhub_faq_cate_create_and_update(self):
|
||||||
|
"""测试创建和更新FAQ分类接口"""
|
||||||
|
with allure.step("1. 创建FAQ分类"):
|
||||||
|
timestamp = int(time.time())
|
||||||
|
create_params = {
|
||||||
|
"title": f"测试FAQ分类_{timestamp}",
|
||||||
|
"lang": "zh_CN",
|
||||||
|
"rank_num": 1,
|
||||||
|
"pid": 0,
|
||||||
|
"status": 1
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(create_params, ensure_ascii=False), name="创建请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
create_resp = self.test_case.kw_joyhub_faq_cate_create_post(**create_params)
|
||||||
|
allure.attach(json.dumps(create_resp, ensure_ascii=False, indent=2), name="创建响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
assert create_resp is not None, "响应为空"
|
||||||
|
assert "code" in create_resp, "响应中缺少code字段"
|
||||||
|
assert create_resp["code"] == 0, f"创建失败,code={create_resp.get('code')}, msg={create_resp.get('msg')}"
|
||||||
|
assert "data" in create_resp, "响应中缺少data字段"
|
||||||
|
assert isinstance(create_resp["data"], int), "data字段不是整数类型"
|
||||||
|
faq_cate_id = create_resp["data"]
|
||||||
|
TestFaqCateManage.faq_cate_id = faq_cate_id
|
||||||
|
logging.info(f"创建FAQ分类成功,ID: {faq_cate_id}")
|
||||||
|
|
||||||
|
with allure.step("2. 调用更新接口"):
|
||||||
|
timestamp = int(time.time())
|
||||||
|
update_params = {
|
||||||
|
"faq_cate_id": faq_cate_id,
|
||||||
|
"title": f"测试FAQ分类_{timestamp}_updated",
|
||||||
|
"lang": "en",
|
||||||
|
"rank_num": 2,
|
||||||
|
"pid": 0,
|
||||||
|
"status": 2
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(update_params, ensure_ascii=False), name="更新请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
update_resp = self.test_case.kw_joyhub_faq_cate_update_put(**update_params)
|
||||||
|
allure.attach(json.dumps(update_resp, ensure_ascii=False, indent=2), name="更新响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证更新响应"):
|
||||||
|
assert update_resp is not None, "响应为空"
|
||||||
|
assert "code" in update_resp, "响应中缺少code字段"
|
||||||
|
assert update_resp["code"] == 0, f"更新失败,code={update_resp.get('code')}, msg={update_resp.get('msg')}"
|
||||||
|
assert "data" in update_resp, "响应中缺少data字段"
|
||||||
|
assert update_resp["data"] is True, "更新FAQ分类失败"
|
||||||
|
logging.info("创建并更新FAQ分类验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证删除FAQ分类")
|
||||||
|
@allure.title("测试删除FAQ分类接口")
|
||||||
|
def test_joyhub_faq_cate_delete_delete(self):
|
||||||
|
"""测试删除FAQ分类接口"""
|
||||||
|
if not TestFaqCateManage.faq_cate_id:
|
||||||
|
pytest.skip("没有可删除的FAQ分类数据")
|
||||||
|
|
||||||
|
with allure.step("1. 调用删除接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_faq_cate_delete_delete(faq_cate_id=TestFaqCateManage.faq_cate_id)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("2. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"删除失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert resp["data"] is True, "删除FAQ分类失败"
|
||||||
|
logging.info("删除FAQ分类验证通过")
|
||||||
210
dulizhan/test_case/TestCase/接口/JoyHub/Joyhub_News.py
Normal file
210
dulizhan/test_case/TestCase/接口/JoyHub/Joyhub_News.py
Normal file
@@ -0,0 +1,210 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
news管理接口测试用例
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import pytest
|
||||||
|
import allure
|
||||||
|
import logging
|
||||||
|
import time
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from dulizhan.library.BusinessKw.JoyHub.NewsManage import NewsManage
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("管理后台 - news管理模块")
|
||||||
|
class TestNewsManage:
|
||||||
|
news_id = None
|
||||||
|
news_cate_id = None
|
||||||
|
token_set = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setup_class(cls):
|
||||||
|
"""在整个测试类开始时登录一次,所有测试用例共享token"""
|
||||||
|
logging.info("=============================================")
|
||||||
|
logging.info("=========== 开始登录,获取Token ============")
|
||||||
|
logging.info("=============================================")
|
||||||
|
|
||||||
|
cls.test_case = NewsManage()
|
||||||
|
username = "joytest"
|
||||||
|
password = "Zhou1599"
|
||||||
|
|
||||||
|
cls.test_case._clear_user_fingerprint(username)
|
||||||
|
|
||||||
|
url = 'https://joyhub-website-manager-api-test.best-envision.com/admin-api/system/auth/login-dev'
|
||||||
|
payload = {'username': username, 'password': password}
|
||||||
|
headers = {'Content-Type': 'application/json', 'tenant-id': '126'}
|
||||||
|
|
||||||
|
response = requests.post(url, json=payload, headers=headers, verify=False, timeout=10)
|
||||||
|
login_response = response.json()
|
||||||
|
|
||||||
|
if login_response and login_response.get('code') == 0:
|
||||||
|
token = login_response.get('data', {}).get('accessToken', '')
|
||||||
|
cls.test_case.set_joyhub_token(token)
|
||||||
|
cls.token_set = True
|
||||||
|
logging.info("登录成功,Token已设置")
|
||||||
|
|
||||||
|
# 获取news分类ID供后续使用
|
||||||
|
from dulizhan.library.BusinessKw.JoyHub.NewsCateManage import NewsCateManage
|
||||||
|
news_cate_manage = NewsCateManage()
|
||||||
|
news_cate_manage.set_joyhub_token(token)
|
||||||
|
cate_page_resp = news_cate_manage.kw_joyhub_news_cate_page_get(page_no=1, page_size=10)
|
||||||
|
if cate_page_resp.get('code') == 0 and cate_page_resp.get('data', {}).get('list'):
|
||||||
|
cls.news_cate_id = cate_page_resp['data']['list'][0].get('id')
|
||||||
|
logging.info(f"获取到news分类ID: {cls.news_cate_id}")
|
||||||
|
else:
|
||||||
|
logging.error(f"登录失败: {login_response}")
|
||||||
|
|
||||||
|
@allure.story("验证登录接口")
|
||||||
|
@allure.title("测试登录接口")
|
||||||
|
def test_joyhub_login_post(self):
|
||||||
|
"""测试登录接口"""
|
||||||
|
assert TestNewsManage.token_set is True, "登录失败,未获取到token"
|
||||||
|
logging.info("登录验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证获得news管理分页")
|
||||||
|
@allure.title("测试获得news管理分页接口")
|
||||||
|
def test_joyhub_news_page_get(self):
|
||||||
|
"""测试获得news管理分页接口"""
|
||||||
|
with allure.step("1. 调用分页接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_news_page_get(page_no=1, page_size=10)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("2. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert "list" in resp["data"], "响应中缺少list字段"
|
||||||
|
assert isinstance(resp["data"]["list"], list), "list字段不是列表类型"
|
||||||
|
logging.info("获得news管理分页验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证获得news管理详情")
|
||||||
|
@allure.title("测试获得news管理详情接口")
|
||||||
|
def test_joyhub_news_get_get(self):
|
||||||
|
"""测试获得news管理详情接口"""
|
||||||
|
with allure.step("1. 从分页获取现有news管理ID"):
|
||||||
|
page_resp = self.test_case.kw_joyhub_news_page_get(page_no=1, page_size=10)
|
||||||
|
assert page_resp.get("code") == 0, f"获取分页失败,code={page_resp.get('code')}, msg={page_resp.get('msg')}"
|
||||||
|
assert page_resp.get("data", {}).get("list"), "没有找到可用的news管理数据"
|
||||||
|
news_id = page_resp["data"]["list"][0].get("id")
|
||||||
|
assert news_id, "news管理ID为空"
|
||||||
|
|
||||||
|
with allure.step("2. 调用获取详情接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_news_get_get(news_id=news_id)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert "id" in resp["data"], "响应中缺少id字段"
|
||||||
|
assert resp["data"]["id"] == news_id, "返回的ID与请求的ID不一致"
|
||||||
|
assert "title" in resp["data"], "响应中缺少title字段"
|
||||||
|
assert isinstance(resp["data"]["title"], str), "title字段不是字符串类型"
|
||||||
|
logging.info("获得news管理详情验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证创建和更新news管理")
|
||||||
|
@allure.title("测试创建和更新news管理接口")
|
||||||
|
def test_joyhub_news_create_and_update(self):
|
||||||
|
"""测试创建和更新news管理接口"""
|
||||||
|
with allure.step("1. 创建news管理"):
|
||||||
|
timestamp = int(time.time())
|
||||||
|
create_params = {
|
||||||
|
"title": f"测试news标题_{timestamp}",
|
||||||
|
"cover_image": {"url": "https://example.com/test.jpg", "name": "test.jpg"},
|
||||||
|
"content": f"<p>测试内容_{timestamp}</p>",
|
||||||
|
"status": 1,
|
||||||
|
"rank_num": 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# 如果有可用的news分类ID,添加关联
|
||||||
|
if TestNewsManage.news_cate_id:
|
||||||
|
create_params["cate_ids"] = [TestNewsManage.news_cate_id]
|
||||||
|
|
||||||
|
allure.attach(json.dumps(create_params, ensure_ascii=False), name="创建请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
create_resp = self.test_case.kw_joyhub_news_create_post(**create_params)
|
||||||
|
allure.attach(json.dumps(create_resp, ensure_ascii=False, indent=2), name="创建响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
assert create_resp is not None, "响应为空"
|
||||||
|
assert "code" in create_resp, "响应中缺少code字段"
|
||||||
|
assert create_resp["code"] == 0, f"创建失败,code={create_resp.get('code')}, msg={create_resp.get('msg')}"
|
||||||
|
assert "data" in create_resp, "响应中缺少data字段"
|
||||||
|
assert isinstance(create_resp["data"], int), "data字段不是整数类型"
|
||||||
|
news_id = create_resp["data"]
|
||||||
|
TestNewsManage.news_id = news_id
|
||||||
|
logging.info(f"创建news管理成功,ID: {news_id}")
|
||||||
|
|
||||||
|
with allure.step("2. 调用更新接口"):
|
||||||
|
timestamp = int(time.time())
|
||||||
|
update_params = {
|
||||||
|
"news_id": news_id,
|
||||||
|
"title": f"测试news标题_{timestamp}_updated",
|
||||||
|
"cover_image": {"url": "https://example.com/test_updated.jpg", "name": "test_updated.jpg"},
|
||||||
|
"content": f"<p>测试内容_{timestamp}_updated</p>",
|
||||||
|
"status": 2,
|
||||||
|
"rank_num": 2
|
||||||
|
}
|
||||||
|
|
||||||
|
# 如果有可用的news分类ID,添加关联
|
||||||
|
if TestNewsManage.news_cate_id:
|
||||||
|
update_params["cate_ids"] = [TestNewsManage.news_cate_id]
|
||||||
|
|
||||||
|
allure.attach(json.dumps(update_params, ensure_ascii=False), name="更新请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
update_resp = self.test_case.kw_joyhub_news_update_put(**update_params)
|
||||||
|
allure.attach(json.dumps(update_resp, ensure_ascii=False, indent=2), name="更新响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证更新响应"):
|
||||||
|
assert update_resp is not None, "响应为空"
|
||||||
|
assert "code" in update_resp, "响应中缺少code字段"
|
||||||
|
assert update_resp["code"] == 0, f"更新失败,code={update_resp.get('code')}, msg={update_resp.get('msg')}"
|
||||||
|
assert "data" in update_resp, "响应中缺少data字段"
|
||||||
|
assert update_resp["data"] is True, "更新news管理失败"
|
||||||
|
logging.info("创建并更新news管理验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证删除news管理")
|
||||||
|
@allure.title("测试删除news管理接口")
|
||||||
|
def test_joyhub_news_delete_delete(self):
|
||||||
|
"""测试删除news管理接口"""
|
||||||
|
if not TestNewsManage.news_id:
|
||||||
|
pytest.skip("没有可删除的news管理数据")
|
||||||
|
|
||||||
|
with allure.step("1. 调用删除接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_news_delete_delete(news_id=TestNewsManage.news_id)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("2. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"删除失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert resp["data"] is True, "删除news管理失败"
|
||||||
|
logging.info("删除news管理验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证获得news分类关联列表")
|
||||||
|
@allure.title("测试获得news分类关联列表接口")
|
||||||
|
def test_joyhub_news_cate_relation_list_get(self):
|
||||||
|
"""测试获得news分类关联列表接口"""
|
||||||
|
with allure.step("1. 从分页获取现有news管理ID"):
|
||||||
|
page_resp = self.test_case.kw_joyhub_news_page_get(page_no=1, page_size=10)
|
||||||
|
assert page_resp.get("code") == 0, f"获取分页失败,code={page_resp.get('code')}, msg={page_resp.get('msg')}"
|
||||||
|
assert page_resp.get("data", {}).get("list"), "没有找到可用的news管理数据"
|
||||||
|
news_id = page_resp["data"]["list"][0].get("id")
|
||||||
|
assert news_id, "news管理ID为空"
|
||||||
|
|
||||||
|
with allure.step("2. 调用获取分类关联列表接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_news_cate_relation_list_get(news_id=news_id)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert isinstance(resp["data"], list), "data字段不是列表类型"
|
||||||
|
logging.info("获得news分类关联列表验证通过")
|
||||||
186
dulizhan/test_case/TestCase/接口/JoyHub/Joyhub_NewsCate.py
Normal file
186
dulizhan/test_case/TestCase/接口/JoyHub/Joyhub_NewsCate.py
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
news分类管理接口测试用例
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import pytest
|
||||||
|
import allure
|
||||||
|
import logging
|
||||||
|
import time
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from dulizhan.library.BusinessKw.JoyHub.NewsCateManage import NewsCateManage
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("管理后台 - news分类管理模块")
|
||||||
|
class TestNewsCateManage:
|
||||||
|
news_cate_id = None
|
||||||
|
created_names = []
|
||||||
|
token_set = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setup_class(cls):
|
||||||
|
"""在整个测试类开始时登录一次,所有测试用例共享token"""
|
||||||
|
logging.info("=============================================")
|
||||||
|
logging.info("=========== 开始登录,获取Token ============")
|
||||||
|
logging.info("=============================================")
|
||||||
|
|
||||||
|
cls.test_case = NewsCateManage()
|
||||||
|
username = "joytest"
|
||||||
|
password = "Zhou1599"
|
||||||
|
|
||||||
|
cls.test_case._clear_user_fingerprint(username)
|
||||||
|
|
||||||
|
url = 'https://joyhub-website-manager-api-test.best-envision.com/admin-api/system/auth/login-dev'
|
||||||
|
payload = {'username': username, 'password': password}
|
||||||
|
headers = {'Content-Type': 'application/json', 'tenant-id': '126'}
|
||||||
|
|
||||||
|
response = requests.post(url, json=payload, headers=headers, verify=False, timeout=10)
|
||||||
|
login_response = response.json()
|
||||||
|
|
||||||
|
if login_response and login_response.get('code') == 0:
|
||||||
|
token = login_response.get('data', {}).get('accessToken', '')
|
||||||
|
cls.test_case.set_joyhub_token(token)
|
||||||
|
cls.token_set = True
|
||||||
|
logging.info("登录成功,Token已设置")
|
||||||
|
else:
|
||||||
|
logging.error(f"登录失败: {login_response}")
|
||||||
|
|
||||||
|
@allure.story("验证登录接口")
|
||||||
|
@allure.title("测试登录接口")
|
||||||
|
def test_joyhub_login_post(self):
|
||||||
|
"""测试登录接口"""
|
||||||
|
assert TestNewsCateManage.token_set is True, "登录失败,未获取到token"
|
||||||
|
logging.info("登录验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证获得news分类分页")
|
||||||
|
@allure.title("测试获得news分类分页接口")
|
||||||
|
def test_joyhub_news_cate_page_get(self):
|
||||||
|
"""测试获得news分类分页接口"""
|
||||||
|
with allure.step("1. 调用分页接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_news_cate_page_get(page_no=1, page_size=10)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("2. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert "list" in resp["data"], "响应中缺少list字段"
|
||||||
|
assert isinstance(resp["data"]["list"], list), "list字段不是列表类型"
|
||||||
|
logging.info("获得news分类分页验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证获得news分类详情")
|
||||||
|
@allure.title("测试获得news分类详情接口")
|
||||||
|
def test_joyhub_news_cate_get_get(self):
|
||||||
|
"""测试获得news分类详情接口"""
|
||||||
|
with allure.step("1. 从分页获取现有news分类ID"):
|
||||||
|
page_resp = self.test_case.kw_joyhub_news_cate_page_get(page_no=1, page_size=10)
|
||||||
|
assert page_resp.get("code") == 0, f"获取分页失败,code={page_resp.get('code')}, msg={page_resp.get('msg')}"
|
||||||
|
assert page_resp.get("data", {}).get("list"), "没有找到可用的news分类数据"
|
||||||
|
news_cate_id = page_resp["data"]["list"][0].get("id")
|
||||||
|
assert news_cate_id, "news分类ID为空"
|
||||||
|
|
||||||
|
with allure.step("2. 调用获取详情接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_news_cate_get_get(news_cate_id=news_cate_id)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert "id" in resp["data"], "响应中缺少id字段"
|
||||||
|
assert resp["data"]["id"] == news_cate_id, "返回的ID与请求的ID不一致"
|
||||||
|
assert "name" in resp["data"], "响应中缺少name字段"
|
||||||
|
assert isinstance(resp["data"]["name"], str), "name字段不是字符串类型"
|
||||||
|
logging.info("获得news分类详情验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证创建和更新news分类")
|
||||||
|
@allure.title("测试创建和更新news分类接口")
|
||||||
|
def test_joyhub_news_cate_create_and_update(self):
|
||||||
|
"""测试创建和更新news分类接口"""
|
||||||
|
with allure.step("1. 创建news分类"):
|
||||||
|
timestamp = int(time.time())
|
||||||
|
created_name = f"测试news分类_{timestamp}"
|
||||||
|
TestNewsCateManage.created_names.append(created_name)
|
||||||
|
|
||||||
|
create_params = {
|
||||||
|
"name": created_name,
|
||||||
|
"status": 1,
|
||||||
|
"rank_num": 1,
|
||||||
|
"cover_image": {"url": "https://example.com/test.jpg", "name": "test.jpg"}
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(create_params, ensure_ascii=False), name="创建请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
create_resp = self.test_case.kw_joyhub_news_cate_create_post(**create_params)
|
||||||
|
allure.attach(json.dumps(create_resp, ensure_ascii=False, indent=2), name="创建响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
assert create_resp is not None, "响应为空"
|
||||||
|
assert "code" in create_resp, "响应中缺少code字段"
|
||||||
|
assert create_resp["code"] == 0, f"创建失败,code={create_resp.get('code')}, msg={create_resp.get('msg')}"
|
||||||
|
assert "data" in create_resp, "响应中缺少data字段"
|
||||||
|
assert isinstance(create_resp["data"], int), "data字段不是整数类型"
|
||||||
|
news_cate_id = create_resp["data"]
|
||||||
|
TestNewsCateManage.news_cate_id = news_cate_id
|
||||||
|
logging.info(f"创建news分类成功,ID: {news_cate_id}")
|
||||||
|
|
||||||
|
with allure.step("2. 调用更新接口"):
|
||||||
|
timestamp = int(time.time())
|
||||||
|
updated_name = f"测试news分类_{timestamp}_updated"
|
||||||
|
TestNewsCateManage.created_names.append(updated_name)
|
||||||
|
|
||||||
|
update_params = {
|
||||||
|
"news_cate_id": news_cate_id,
|
||||||
|
"name": updated_name,
|
||||||
|
"status": 2,
|
||||||
|
"rank_num": 2,
|
||||||
|
"cover_image": {"url": "https://example.com/test_updated.jpg", "name": "test_updated.jpg"}
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(update_params, ensure_ascii=False), name="更新请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
update_resp = self.test_case.kw_joyhub_news_cate_update_put(**update_params)
|
||||||
|
allure.attach(json.dumps(update_resp, ensure_ascii=False, indent=2), name="更新响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证更新响应"):
|
||||||
|
assert update_resp is not None, "响应为空"
|
||||||
|
assert "code" in update_resp, "响应中缺少code字段"
|
||||||
|
assert update_resp["code"] == 0, f"更新失败,code={update_resp.get('code')}, msg={update_resp.get('msg')}"
|
||||||
|
assert "data" in update_resp, "响应中缺少data字段"
|
||||||
|
assert update_resp["data"] is True, "更新news分类失败"
|
||||||
|
logging.info("创建并更新news分类验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证删除news分类")
|
||||||
|
@allure.title("测试删除news分类接口")
|
||||||
|
def test_joyhub_news_cate_delete_delete(self):
|
||||||
|
"""测试删除news分类接口"""
|
||||||
|
if not TestNewsCateManage.news_cate_id:
|
||||||
|
pytest.skip("没有可删除的news分类数据")
|
||||||
|
|
||||||
|
with allure.step("1. 调用删除接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_news_cate_delete_delete(news_cate_id=TestNewsCateManage.news_cate_id)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("2. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"删除失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert resp["data"] is True, "删除news分类失败"
|
||||||
|
logging.info("删除news分类验证通过")
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def teardown_class(cls):
|
||||||
|
"""在整个测试类结束时清理测试数据"""
|
||||||
|
logging.info("=============================================")
|
||||||
|
logging.info("=========== 清理测试数据 ============")
|
||||||
|
logging.info("=============================================")
|
||||||
|
|
||||||
|
# 从数据库表jh_news_cate中删除测试数据
|
||||||
|
for name in cls.created_names:
|
||||||
|
cls.test_case.clean_test_data_from_db(name)
|
||||||
|
|
||||||
|
# 额外清理所有包含"测试news分类"的记录
|
||||||
|
cls.test_case.clean_test_data_from_db("测试news分类")
|
||||||
490
dulizhan/test_case/TestCase/接口/JoyHub/Joyhub_Product.py
Normal file
490
dulizhan/test_case/TestCase/接口/JoyHub/Joyhub_Product.py
Normal file
@@ -0,0 +1,490 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
产品管理接口测试用例
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import pytest
|
||||||
|
import allure
|
||||||
|
import logging
|
||||||
|
import time
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from dulizhan.library.BusinessKw.JoyHub.ProductManage import ProductManage
|
||||||
|
from dulizhan.library.BusinessKw.JoyHub.ProductCateManage import ProductCateManage
|
||||||
|
from base_framework.public_tools.pgsqlhelper import PgSqlHelper
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("管理后台 - 产品管理模块")
|
||||||
|
class TestProductManage:
|
||||||
|
product_id = None
|
||||||
|
product_cate_id = None
|
||||||
|
shipping_template_id = None
|
||||||
|
brand_id = None
|
||||||
|
product_attr_type_id = None
|
||||||
|
product_attr_data_id = None
|
||||||
|
token_set = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setup_class(cls):
|
||||||
|
"""在整个测试类开始时登录一次,所有测试用例共享token"""
|
||||||
|
logging.info("=============================================")
|
||||||
|
logging.info("=========== 开始登录,获取Token ============")
|
||||||
|
logging.info("=============================================")
|
||||||
|
|
||||||
|
cls.test_case = ProductManage()
|
||||||
|
username = "joytest"
|
||||||
|
password = "Zhou1599"
|
||||||
|
|
||||||
|
cls.test_case._clear_user_fingerprint(username)
|
||||||
|
|
||||||
|
url = 'https://joyhub-website-manager-api-test.best-envision.com/admin-api/system/auth/login-dev'
|
||||||
|
payload = {'username': username, 'password': password}
|
||||||
|
headers = {'Content-Type': 'application/json', 'tenant-id': '126'}
|
||||||
|
|
||||||
|
response = requests.post(url, json=payload, headers=headers, verify=False, timeout=10)
|
||||||
|
login_response = response.json()
|
||||||
|
|
||||||
|
if login_response and login_response.get('code') == 0:
|
||||||
|
token = login_response.get('data', {}).get('accessToken', '')
|
||||||
|
cls.test_case.set_joyhub_token(token)
|
||||||
|
cls.token_set = True
|
||||||
|
logging.info("登录成功,Token已设置")
|
||||||
|
|
||||||
|
# 获取产品分类ID
|
||||||
|
product_cate_manage = ProductCateManage()
|
||||||
|
product_cate_manage.set_joyhub_token(token)
|
||||||
|
cate_page_resp = product_cate_manage.kw_joyhub_product_cate_page_get(page_no=1, page_size=50)
|
||||||
|
if cate_page_resp.get('code') == 0 and cate_page_resp.get('data', {}).get('list'):
|
||||||
|
for cate_item in cate_page_resp['data']['list']:
|
||||||
|
if cate_item.get('cateType') == 1:
|
||||||
|
cls.product_cate_id = cate_item.get('id')
|
||||||
|
break
|
||||||
|
if cls.product_cate_id is None:
|
||||||
|
cls.product_cate_id = cate_page_resp['data']['list'][0].get('id')
|
||||||
|
logging.info(f"获取到产品分类ID: {cls.product_cate_id}")
|
||||||
|
|
||||||
|
# 获取运费模板ID和品牌ID
|
||||||
|
try:
|
||||||
|
db_helper = PgSqlHelper()
|
||||||
|
logging.info("开始连接数据库获取运费模板ID和品牌ID")
|
||||||
|
|
||||||
|
# 从jh_shipping_template表获取运费模板ID(使用joyhub数据库)
|
||||||
|
shipping_sql = "SELECT id FROM jh_shipping_template WHERE deleted = 0 LIMIT 1"
|
||||||
|
logging.info(f"执行SQL: {shipping_sql}")
|
||||||
|
shipping_result = db_helper.select_one(shipping_sql, choose_db='joyhub')
|
||||||
|
logging.info(f"运费模板查询结果: {shipping_result}")
|
||||||
|
if shipping_result:
|
||||||
|
cls.shipping_template_id = shipping_result.get('id')
|
||||||
|
logging.info(f"从数据库获取到运费模板ID: {cls.shipping_template_id}")
|
||||||
|
else:
|
||||||
|
logging.warning("数据库中未找到运费模板数据")
|
||||||
|
|
||||||
|
# 从jh_after_sales_brand表获取品牌ID(使用joyhub数据库)
|
||||||
|
brand_sql = "SELECT id FROM jh_after_sales_brand WHERE deleted = 0 LIMIT 1"
|
||||||
|
logging.info(f"执行SQL: {brand_sql}")
|
||||||
|
brand_result = db_helper.select_one(brand_sql, choose_db='joyhub')
|
||||||
|
logging.info(f"品牌查询结果: {brand_result}")
|
||||||
|
if brand_result:
|
||||||
|
cls.brand_id = brand_result.get('id')
|
||||||
|
logging.info(f"从数据库获取到品牌ID: {cls.brand_id}")
|
||||||
|
else:
|
||||||
|
logging.warning("数据库中未找到品牌数据")
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"从数据库获取运费模板ID和品牌ID失败: {e}")
|
||||||
|
import traceback
|
||||||
|
logging.error(traceback.format_exc())
|
||||||
|
|
||||||
|
# 获取现有产品ID用于测试
|
||||||
|
product_page_resp = cls.test_case.kw_joyhub_product_page_get(page_no=1, page_size=10)
|
||||||
|
if product_page_resp.get('code') == 0 and product_page_resp.get('data', {}).get('list'):
|
||||||
|
cls.product_id = product_page_resp['data']['list'][0].get('id')
|
||||||
|
logging.info(f"获取到现有产品ID: {cls.product_id}")
|
||||||
|
|
||||||
|
# 获取产品属性类型ID和属性值ID
|
||||||
|
from dulizhan.library.BusinessKw.JoyHub.ProductAttrManage import ProductAttrManage
|
||||||
|
product_attr_manage = ProductAttrManage()
|
||||||
|
product_attr_manage.set_joyhub_token(token)
|
||||||
|
|
||||||
|
attr_type_page_resp = product_attr_manage.kw_joyhub_product_attr_type_page_get(page_no=1, page_size=10)
|
||||||
|
if attr_type_page_resp.get('code') == 0 and attr_type_page_resp.get('data', {}).get('list'):
|
||||||
|
cls.product_attr_type_id = attr_type_page_resp['data']['list'][0].get('id')
|
||||||
|
logging.info(f"获取到产品属性类型ID: {cls.product_attr_type_id}")
|
||||||
|
|
||||||
|
# 获取该属性类型下的属性值
|
||||||
|
attr_data_page_resp = product_attr_manage.kw_joyhub_product_attr_data_page_get(
|
||||||
|
page_no=1, page_size=10, productAttrTypeId=cls.product_attr_type_id
|
||||||
|
)
|
||||||
|
if attr_data_page_resp.get('code') == 0 and attr_data_page_resp.get('data', {}).get('list'):
|
||||||
|
cls.product_attr_data_id = attr_data_page_resp['data']['list'][0].get('id')
|
||||||
|
logging.info(f"获取到产品属性值ID: {cls.product_attr_data_id}")
|
||||||
|
else:
|
||||||
|
# 如果没有属性值,创建一个
|
||||||
|
timestamp = int(time.time())
|
||||||
|
create_attr_data_resp = product_attr_manage.kw_joyhub_product_attr_data_create_post(
|
||||||
|
product_attr_type_id=cls.product_attr_type_id,
|
||||||
|
attr_value=f"测试属性值_{timestamp}"
|
||||||
|
)
|
||||||
|
if create_attr_data_resp.get('code') == 0:
|
||||||
|
cls.product_attr_data_id = create_attr_data_resp['data']
|
||||||
|
logging.info(f"创建产品属性值成功,ID: {cls.product_attr_data_id}")
|
||||||
|
else:
|
||||||
|
# 如果没有产品属性类型,创建一个
|
||||||
|
timestamp = int(time.time())
|
||||||
|
create_attr_type_resp = product_attr_manage.kw_joyhub_product_attr_type_create_post(
|
||||||
|
name=f"测试产品属性_{timestamp}",
|
||||||
|
type=2,
|
||||||
|
status=1
|
||||||
|
)
|
||||||
|
if create_attr_type_resp.get('code') == 0:
|
||||||
|
cls.product_attr_type_id = create_attr_type_resp['data']
|
||||||
|
logging.info(f"创建产品属性类型成功,ID: {cls.product_attr_type_id}")
|
||||||
|
|
||||||
|
# 创建属性值
|
||||||
|
create_attr_data_resp = product_attr_manage.kw_joyhub_product_attr_data_create_post(
|
||||||
|
product_attr_type_id=cls.product_attr_type_id,
|
||||||
|
attr_value=f"测试属性值_{timestamp}"
|
||||||
|
)
|
||||||
|
if create_attr_data_resp.get('code') == 0:
|
||||||
|
cls.product_attr_data_id = create_attr_data_resp['data']
|
||||||
|
logging.info(f"创建产品属性值成功,ID: {cls.product_attr_data_id}")
|
||||||
|
else:
|
||||||
|
logging.error(f"登录失败: {login_response}")
|
||||||
|
|
||||||
|
@allure.story("验证登录接口")
|
||||||
|
@allure.title("测试登录接口")
|
||||||
|
def test_joyhub_login_post(self):
|
||||||
|
"""测试登录接口"""
|
||||||
|
assert TestProductManage.token_set is True, "登录失败,未获取到token"
|
||||||
|
logging.info("登录验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证获得产品分页")
|
||||||
|
@allure.title("测试获得产品分页接口")
|
||||||
|
def test_joyhub_product_page_get(self):
|
||||||
|
"""测试获得产品分页接口"""
|
||||||
|
with allure.step("1. 调用分页接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_product_page_get(page_no=1, page_size=10)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("2. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert "list" in resp["data"], "响应中缺少list字段"
|
||||||
|
assert isinstance(resp["data"]["list"], list), "list字段不是列表类型"
|
||||||
|
logging.info("获得产品分页验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证获得产品详情")
|
||||||
|
@allure.title("测试获得产品详情接口")
|
||||||
|
def test_joyhub_product_get_get(self):
|
||||||
|
"""测试获得产品详情接口"""
|
||||||
|
with allure.step("1. 从分页获取现有产品ID"):
|
||||||
|
page_resp = self.test_case.kw_joyhub_product_page_get(page_no=1, page_size=10)
|
||||||
|
assert page_resp.get("code") == 0, f"获取分页失败,code={page_resp.get('code')}, msg={page_resp.get('msg')}"
|
||||||
|
assert page_resp.get("data", {}).get("list"), "没有找到可用的产品数据"
|
||||||
|
product_id = page_resp["data"]["list"][0].get("id")
|
||||||
|
assert product_id, "产品ID为空"
|
||||||
|
|
||||||
|
with allure.step("2. 调用获取详情接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_product_get_get(product_id=product_id)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert "id" in resp["data"], "响应中缺少id字段"
|
||||||
|
assert resp["data"]["id"] == product_id, "返回的ID与请求的ID不一致"
|
||||||
|
assert "productName" in resp["data"], "响应中缺少productName字段"
|
||||||
|
assert isinstance(resp["data"]["productName"], str), "productName字段不是字符串类型"
|
||||||
|
logging.info("获得产品详情验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证获得产品规格类型关联列表")
|
||||||
|
@allure.title("测试获得产品规格类型关联列表接口")
|
||||||
|
def test_joyhub_product_product_attr_list_by_product_id_get(self):
|
||||||
|
"""测试获得产品规格类型关联列表接口"""
|
||||||
|
with allure.step("1. 从分页获取现有产品ID"):
|
||||||
|
page_resp = self.test_case.kw_joyhub_product_page_get(page_no=1, page_size=10)
|
||||||
|
assert page_resp.get("code") == 0, f"获取分页失败,code={page_resp.get('code')}, msg={page_resp.get('msg')}"
|
||||||
|
assert page_resp.get("data", {}).get("list"), "没有找到可用的产品数据"
|
||||||
|
product_id = page_resp["data"]["list"][0].get("id")
|
||||||
|
assert product_id, "产品ID为空"
|
||||||
|
|
||||||
|
with allure.step("2. 调用获取产品规格类型关联列表接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_product_product_attr_list_by_product_id_get(product_id=product_id)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert isinstance(resp["data"], list), "data字段不是列表类型"
|
||||||
|
logging.info("获得产品规格类型关联列表验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证获得产品详情列表")
|
||||||
|
@allure.title("测试获得产品详情列表接口")
|
||||||
|
def test_joyhub_product_product_detail_list_by_product_id_get(self):
|
||||||
|
"""测试获得产品详情列表接口"""
|
||||||
|
with allure.step("1. 从分页获取现有产品ID"):
|
||||||
|
page_resp = self.test_case.kw_joyhub_product_page_get(page_no=1, page_size=10)
|
||||||
|
assert page_resp.get("code") == 0, f"获取分页失败,code={page_resp.get('code')}, msg={page_resp.get('msg')}"
|
||||||
|
assert page_resp.get("data", {}).get("list"), "没有找到可用的产品数据"
|
||||||
|
product_id = page_resp["data"]["list"][0].get("id")
|
||||||
|
assert product_id, "产品ID为空"
|
||||||
|
|
||||||
|
with allure.step("2. 调用获取产品详情列表接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_product_product_detail_list_by_product_id_get(product_id=product_id)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert isinstance(resp["data"], list), "data字段不是列表类型"
|
||||||
|
logging.info("获得产品详情列表验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证获得产品规格列表")
|
||||||
|
@allure.title("测试获得产品规格列表接口")
|
||||||
|
def test_joyhub_product_product_sku_list_by_product_id_get(self):
|
||||||
|
"""测试获得产品规格列表接口"""
|
||||||
|
with allure.step("1. 从分页获取现有产品ID"):
|
||||||
|
page_resp = self.test_case.kw_joyhub_product_page_get(page_no=1, page_size=10)
|
||||||
|
assert page_resp.get("code") == 0, f"获取分页失败,code={page_resp.get('code')}, msg={page_resp.get('msg')}"
|
||||||
|
assert page_resp.get("data", {}).get("list"), "没有找到可用的产品数据"
|
||||||
|
product_id = page_resp["data"]["list"][0].get("id")
|
||||||
|
assert product_id, "产品ID为空"
|
||||||
|
|
||||||
|
with allure.step("2. 调用获取产品规格列表接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_product_product_sku_list_by_product_id_get(product_id=product_id)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert isinstance(resp["data"], list), "data字段不是列表类型"
|
||||||
|
logging.info("获得产品规格列表验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证创建和更新产品")
|
||||||
|
@allure.title("测试创建和更新产品接口")
|
||||||
|
def test_joyhub_product_create_and_update(self):
|
||||||
|
"""测试创建和更新产品接口"""
|
||||||
|
# 检查必要的前置数据
|
||||||
|
logging.info(f"前置数据状态 - product_cate_id: {TestProductManage.product_cate_id}, "
|
||||||
|
f"shipping_template_id: {TestProductManage.shipping_template_id}, "
|
||||||
|
f"brand_id: {TestProductManage.brand_id}, "
|
||||||
|
f"product_attr_type_id: {TestProductManage.product_attr_type_id}, "
|
||||||
|
f"product_attr_data_id: {TestProductManage.product_attr_data_id}")
|
||||||
|
|
||||||
|
# 如果缺少必要数据,则跳过测试
|
||||||
|
if not TestProductManage.product_cate_id:
|
||||||
|
pytest.skip("缺少产品分类ID")
|
||||||
|
if not TestProductManage.shipping_template_id:
|
||||||
|
pytest.skip("缺少运费模板ID")
|
||||||
|
if not TestProductManage.brand_id:
|
||||||
|
pytest.skip("缺少品牌ID")
|
||||||
|
if not all([TestProductManage.product_attr_type_id, TestProductManage.product_attr_data_id]):
|
||||||
|
pytest.skip("缺少产品属性类型或属性值")
|
||||||
|
|
||||||
|
with allure.step("1. 创建产品"):
|
||||||
|
timestamp = int(time.time())
|
||||||
|
|
||||||
|
# 构建产品规格类型关联列表
|
||||||
|
product_attrs = [{
|
||||||
|
"id": 0,
|
||||||
|
"productId": 0,
|
||||||
|
"productAttrTypeId": TestProductManage.product_attr_type_id,
|
||||||
|
"productAttrDataId": TestProductManage.product_attr_data_id
|
||||||
|
}]
|
||||||
|
|
||||||
|
image_obj = {
|
||||||
|
"url": "https://img.joyhub.net/official_jub/20260413/resized_E031_1776065842307.png",
|
||||||
|
"name": None,
|
||||||
|
"alt": None
|
||||||
|
}
|
||||||
|
|
||||||
|
# 构建产品详情列表
|
||||||
|
product_details = [{
|
||||||
|
"id": 0,
|
||||||
|
"productAttrTypeId": TestProductManage.product_attr_type_id,
|
||||||
|
"productAttrDataId": TestProductManage.product_attr_data_id,
|
||||||
|
"isFeatured": 1,
|
||||||
|
"productColor": f"自动化颜色_{timestamp}",
|
||||||
|
"productColorCard": ["#b2b8bf"],
|
||||||
|
"coverImage": image_obj,
|
||||||
|
"coverProductImage": image_obj,
|
||||||
|
"categoryImage": image_obj,
|
||||||
|
"productImages": [image_obj],
|
||||||
|
"description": f"自动化产品详情_{timestamp}"
|
||||||
|
}]
|
||||||
|
|
||||||
|
# 构建产品规格列表
|
||||||
|
product_skus = [{
|
||||||
|
"id": 0,
|
||||||
|
"isFeatured": 1,
|
||||||
|
"skuNo": [f"AUTO{timestamp}"],
|
||||||
|
"productPrice": 100,
|
||||||
|
"exchangePoints": 0,
|
||||||
|
"productOriginalPrice": 120,
|
||||||
|
"stockNum": 100,
|
||||||
|
"status": 1,
|
||||||
|
"productAttrDataIds": [TestProductManage.product_attr_data_id]
|
||||||
|
}]
|
||||||
|
|
||||||
|
create_params = {
|
||||||
|
"product_name": f"测试产品_{timestamp}",
|
||||||
|
"product_cate_id": TestProductManage.product_cate_id,
|
||||||
|
"shipping_template_id": TestProductManage.shipping_template_id,
|
||||||
|
"route": f"/test/product/{timestamp}",
|
||||||
|
"intro": f"测试产品简介_{timestamp}",
|
||||||
|
"brand_id": TestProductManage.brand_id,
|
||||||
|
"product_attrs": product_attrs,
|
||||||
|
"product_skus": product_skus,
|
||||||
|
"product_details": product_details,
|
||||||
|
"status": 1
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(create_params, ensure_ascii=False), name="创建请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
create_resp = self.test_case.kw_joyhub_product_create_post(**create_params)
|
||||||
|
allure.attach(json.dumps(create_resp, ensure_ascii=False, indent=2), name="创建响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
assert create_resp is not None, "响应为空"
|
||||||
|
assert "code" in create_resp, "响应中缺少code字段"
|
||||||
|
assert create_resp["code"] == 0, f"创建失败,code={create_resp.get('code')}, msg={create_resp.get('msg')}"
|
||||||
|
assert "data" in create_resp, "响应中缺少data字段"
|
||||||
|
assert isinstance(create_resp["data"], int), "data字段不是整数类型"
|
||||||
|
product_id = create_resp["data"]
|
||||||
|
TestProductManage.product_id = product_id
|
||||||
|
logging.info(f"创建产品成功,ID: {product_id}")
|
||||||
|
|
||||||
|
with allure.step("2. 调用更新接口"):
|
||||||
|
timestamp = int(time.time())
|
||||||
|
|
||||||
|
# 更新产品规格类型关联列表
|
||||||
|
product_attrs = [{
|
||||||
|
"id": 0,
|
||||||
|
"productId": product_id,
|
||||||
|
"productAttrTypeId": TestProductManage.product_attr_type_id,
|
||||||
|
"productAttrDataId": TestProductManage.product_attr_data_id
|
||||||
|
}]
|
||||||
|
|
||||||
|
image_obj = {
|
||||||
|
"url": "https://img.joyhub.net/official_jub/20260413/resized_E031_1776065842307.png",
|
||||||
|
"name": None,
|
||||||
|
"alt": None
|
||||||
|
}
|
||||||
|
|
||||||
|
# 更新产品详情列表
|
||||||
|
product_details = [{
|
||||||
|
"id": 0,
|
||||||
|
"productAttrTypeId": TestProductManage.product_attr_type_id,
|
||||||
|
"productAttrDataId": TestProductManage.product_attr_data_id,
|
||||||
|
"isFeatured": 1,
|
||||||
|
"productColor": f"自动化颜色_{timestamp}_updated",
|
||||||
|
"productColorCard": ["#b2b8bf"],
|
||||||
|
"coverImage": image_obj,
|
||||||
|
"coverProductImage": image_obj,
|
||||||
|
"categoryImage": image_obj,
|
||||||
|
"productImages": [image_obj],
|
||||||
|
"description": f"自动化产品详情_{timestamp}_updated"
|
||||||
|
}]
|
||||||
|
|
||||||
|
# 更新产品规格列表
|
||||||
|
product_skus = [{
|
||||||
|
"id": 0,
|
||||||
|
"isFeatured": 1,
|
||||||
|
"skuNo": [f"AUTO{timestamp}U"],
|
||||||
|
"productPrice": 200,
|
||||||
|
"exchangePoints": 0,
|
||||||
|
"productOriginalPrice": 220,
|
||||||
|
"stockNum": 200,
|
||||||
|
"status": 1,
|
||||||
|
"productAttrDataIds": [TestProductManage.product_attr_data_id]
|
||||||
|
}]
|
||||||
|
|
||||||
|
update_params = {
|
||||||
|
"product_id": product_id,
|
||||||
|
"product_name": f"测试产品_{timestamp}_updated",
|
||||||
|
"product_cate_id": TestProductManage.product_cate_id,
|
||||||
|
"shipping_template_id": TestProductManage.shipping_template_id,
|
||||||
|
"route": f"/test/product/{timestamp}_updated",
|
||||||
|
"intro": f"测试产品简介_{timestamp}_updated",
|
||||||
|
"brand_id": TestProductManage.brand_id,
|
||||||
|
"product_attrs": product_attrs,
|
||||||
|
"product_skus": product_skus,
|
||||||
|
"product_details": product_details,
|
||||||
|
"status": 2
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(update_params, ensure_ascii=False), name="更新请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
update_resp = self.test_case.kw_joyhub_product_update_put(**update_params)
|
||||||
|
allure.attach(json.dumps(update_resp, ensure_ascii=False, indent=2), name="更新响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证更新响应"):
|
||||||
|
assert update_resp is not None, "响应为空"
|
||||||
|
assert "code" in update_resp, "响应中缺少code字段"
|
||||||
|
assert update_resp["code"] == 0, f"更新失败,code={update_resp.get('code')}, msg={update_resp.get('msg')}"
|
||||||
|
assert "data" in update_resp, "响应中缺少data字段"
|
||||||
|
assert update_resp["data"] is True, "更新产品失败"
|
||||||
|
logging.info("创建并更新产品验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证批量上下架产品")
|
||||||
|
@allure.title("测试批量上下架产品接口")
|
||||||
|
def test_joyhub_product_change_status_put(self):
|
||||||
|
"""测试批量上下架产品接口"""
|
||||||
|
if not TestProductManage.product_id:
|
||||||
|
pytest.skip("没有可修改状态的产品数据")
|
||||||
|
|
||||||
|
with allure.step("1. 调用批量上架接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_product_change_status_put(
|
||||||
|
ids=[TestProductManage.product_id],
|
||||||
|
status=1
|
||||||
|
)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("2. 验证上架响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"批量上架失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert resp["data"] is True, "批量上架产品失败"
|
||||||
|
|
||||||
|
with allure.step("3. 调用批量下架接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_product_change_status_put(
|
||||||
|
ids=[TestProductManage.product_id],
|
||||||
|
status=2
|
||||||
|
)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("4. 验证下架响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"批量下架失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert resp["data"] is True, "批量下架产品失败"
|
||||||
|
logging.info("批量上下架产品验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证删除产品")
|
||||||
|
@allure.title("测试删除产品接口")
|
||||||
|
def test_joyhub_product_delete_delete(self):
|
||||||
|
"""测试删除产品接口"""
|
||||||
|
if not TestProductManage.product_id:
|
||||||
|
pytest.skip("没有可删除的产品数据")
|
||||||
|
|
||||||
|
with allure.step("1. 调用删除接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_product_delete_delete(product_id=TestProductManage.product_id)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("2. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"删除失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert resp["data"] is True, "删除产品失败"
|
||||||
|
logging.info("删除产品验证通过")
|
||||||
320
dulizhan/test_case/TestCase/接口/JoyHub/Joyhub_ProductAttr.py
Normal file
320
dulizhan/test_case/TestCase/接口/JoyHub/Joyhub_ProductAttr.py
Normal file
@@ -0,0 +1,320 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
产品属性+产品属性值管理接口测试用例
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import pytest
|
||||||
|
import allure
|
||||||
|
import logging
|
||||||
|
import time
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from dulizhan.library.BusinessKw.JoyHub.ProductAttrManage import ProductAttrManage
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("管理后台 - 产品属性+产品属性值管理模块")
|
||||||
|
class TestProductAttrManage:
|
||||||
|
product_attr_type_id = None
|
||||||
|
product_attr_data_id = None
|
||||||
|
token_set = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setup_class(cls):
|
||||||
|
"""在整个测试类开始时登录一次,所有测试用例共享token"""
|
||||||
|
logging.info("=============================================")
|
||||||
|
logging.info("=========== 开始登录,获取Token ============")
|
||||||
|
logging.info("=============================================")
|
||||||
|
|
||||||
|
cls.test_case = ProductAttrManage()
|
||||||
|
username = "joytest"
|
||||||
|
password = "Zhou1599"
|
||||||
|
|
||||||
|
cls.test_case._clear_user_fingerprint(username)
|
||||||
|
|
||||||
|
url = 'https://joyhub-website-manager-api-test.best-envision.com/admin-api/system/auth/login-dev'
|
||||||
|
payload = {'username': username, 'password': password}
|
||||||
|
headers = {'Content-Type': 'application/json', 'tenant-id': '126'}
|
||||||
|
|
||||||
|
response = requests.post(url, json=payload, headers=headers, verify=False, timeout=10)
|
||||||
|
login_response = response.json()
|
||||||
|
|
||||||
|
if login_response and login_response.get('code') == 0:
|
||||||
|
token = login_response.get('data', {}).get('accessToken', '')
|
||||||
|
cls.test_case.set_joyhub_token(token)
|
||||||
|
cls.token_set = True
|
||||||
|
logging.info("登录成功,Token已设置")
|
||||||
|
else:
|
||||||
|
logging.error(f"登录失败: {login_response}")
|
||||||
|
|
||||||
|
@allure.story("验证登录接口")
|
||||||
|
@allure.title("测试登录接口")
|
||||||
|
def test_joyhub_login_post(self):
|
||||||
|
"""测试登录接口"""
|
||||||
|
assert TestProductAttrManage.token_set is True, "登录失败,未获取到token"
|
||||||
|
logging.info("登录验证通过")
|
||||||
|
|
||||||
|
# ============ 产品属性测试用例 ============
|
||||||
|
|
||||||
|
@allure.story("验证获得产品属性分页")
|
||||||
|
@allure.title("测试获得产品属性分页接口")
|
||||||
|
def test_joyhub_product_attr_type_page_get(self):
|
||||||
|
"""测试获得产品属性分页接口"""
|
||||||
|
with allure.step("1. 调用分页接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_product_attr_type_page_get(page_no=1, page_size=10)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("2. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert "list" in resp["data"], "响应中缺少list字段"
|
||||||
|
assert isinstance(resp["data"]["list"], list), "list字段不是列表类型"
|
||||||
|
logging.info("获得产品属性分页验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证获得产品属性详情")
|
||||||
|
@allure.title("测试获得产品属性详情接口")
|
||||||
|
def test_joyhub_product_attr_type_get_get(self):
|
||||||
|
"""测试获得产品属性详情接口"""
|
||||||
|
with allure.step("1. 从分页获取现有产品属性ID"):
|
||||||
|
page_resp = self.test_case.kw_joyhub_product_attr_type_page_get(page_no=1, page_size=10)
|
||||||
|
assert page_resp.get("code") == 0, f"获取分页失败,code={page_resp.get('code')}, msg={page_resp.get('msg')}"
|
||||||
|
assert page_resp.get("data", {}).get("list"), "没有找到可用的产品属性数据"
|
||||||
|
product_attr_type_id = page_resp["data"]["list"][0].get("id")
|
||||||
|
assert product_attr_type_id, "产品属性ID为空"
|
||||||
|
|
||||||
|
with allure.step("2. 调用获取详情接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_product_attr_type_get_get(product_attr_type_id=product_attr_type_id)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert "id" in resp["data"], "响应中缺少id字段"
|
||||||
|
assert resp["data"]["id"] == product_attr_type_id, "返回的ID与请求的ID不一致"
|
||||||
|
assert "name" in resp["data"], "响应中缺少name字段"
|
||||||
|
assert isinstance(resp["data"]["name"], str), "name字段不是字符串类型"
|
||||||
|
logging.info("获得产品属性详情验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证创建和更新产品属性")
|
||||||
|
@allure.title("测试创建和更新产品属性接口")
|
||||||
|
def test_joyhub_product_attr_type_create_and_update(self):
|
||||||
|
"""测试创建和更新产品属性接口"""
|
||||||
|
with allure.step("1. 创建产品属性"):
|
||||||
|
timestamp = int(time.time())
|
||||||
|
create_params = {
|
||||||
|
"name": f"测试产品属性_{timestamp}",
|
||||||
|
"type": 2,
|
||||||
|
"status": 1,
|
||||||
|
"remark": f"测试备注_{timestamp}",
|
||||||
|
"rank_num": 1
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(create_params, ensure_ascii=False), name="创建请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
create_resp = self.test_case.kw_joyhub_product_attr_type_create_post(**create_params)
|
||||||
|
allure.attach(json.dumps(create_resp, ensure_ascii=False, indent=2), name="创建响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
assert create_resp is not None, "响应为空"
|
||||||
|
assert "code" in create_resp, "响应中缺少code字段"
|
||||||
|
assert create_resp["code"] == 0, f"创建失败,code={create_resp.get('code')}, msg={create_resp.get('msg')}"
|
||||||
|
assert "data" in create_resp, "响应中缺少data字段"
|
||||||
|
assert isinstance(create_resp["data"], int), "data字段不是整数类型"
|
||||||
|
product_attr_type_id = create_resp["data"]
|
||||||
|
TestProductAttrManage.product_attr_type_id = product_attr_type_id
|
||||||
|
logging.info(f"创建产品属性成功,ID: {product_attr_type_id}")
|
||||||
|
|
||||||
|
with allure.step("2. 调用更新接口"):
|
||||||
|
timestamp = int(time.time())
|
||||||
|
update_params = {
|
||||||
|
"product_attr_type_id": product_attr_type_id,
|
||||||
|
"name": f"测试产品属性_{timestamp}_updated",
|
||||||
|
"type": 2,
|
||||||
|
"status": 2,
|
||||||
|
"remark": f"测试备注_{timestamp}_updated",
|
||||||
|
"rank_num": 2
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(update_params, ensure_ascii=False), name="更新请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
update_resp = self.test_case.kw_joyhub_product_attr_type_update_put(**update_params)
|
||||||
|
allure.attach(json.dumps(update_resp, ensure_ascii=False, indent=2), name="更新响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证更新响应"):
|
||||||
|
assert update_resp is not None, "响应为空"
|
||||||
|
assert "code" in update_resp, "响应中缺少code字段"
|
||||||
|
assert update_resp["code"] == 0, f"更新失败,code={update_resp.get('code')}, msg={update_resp.get('msg')}"
|
||||||
|
assert "data" in update_resp, "响应中缺少data字段"
|
||||||
|
assert update_resp["data"] is True, "更新产品属性失败"
|
||||||
|
logging.info("创建并更新产品属性验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证修改产品属性状态")
|
||||||
|
@allure.title("测试修改产品属性状态接口")
|
||||||
|
def test_joyhub_product_attr_type_change_status_put(self):
|
||||||
|
"""测试修改产品属性状态接口"""
|
||||||
|
if not TestProductAttrManage.product_attr_type_id:
|
||||||
|
pytest.skip("没有可修改状态的产品属性数据")
|
||||||
|
|
||||||
|
with allure.step("1. 调用修改状态接口(启用)"):
|
||||||
|
resp = self.test_case.kw_joyhub_product_attr_type_change_status_put(
|
||||||
|
product_attr_type_id=TestProductAttrManage.product_attr_type_id,
|
||||||
|
status=1
|
||||||
|
)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("2. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"修改状态失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert resp["data"] is True, "修改产品属性状态失败"
|
||||||
|
logging.info("修改产品属性状态验证通过")
|
||||||
|
|
||||||
|
# ============ 产品属性值测试用例 ============
|
||||||
|
|
||||||
|
@allure.story("验证获得产品属性值分页")
|
||||||
|
@allure.title("测试获得产品属性值分页接口")
|
||||||
|
def test_joyhub_product_attr_data_page_get(self):
|
||||||
|
"""测试获得产品属性值分页接口"""
|
||||||
|
with allure.step("1. 调用分页接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_product_attr_data_page_get(page_no=1, page_size=10)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("2. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert "list" in resp["data"], "响应中缺少list字段"
|
||||||
|
assert isinstance(resp["data"]["list"], list), "list字段不是列表类型"
|
||||||
|
logging.info("获得产品属性值分页验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证获得产品属性值详情")
|
||||||
|
@allure.title("测试获得产品属性值详情接口")
|
||||||
|
def test_joyhub_product_attr_data_get_get(self):
|
||||||
|
"""测试获得产品属性值详情接口"""
|
||||||
|
with allure.step("1. 从分页获取现有产品属性值ID"):
|
||||||
|
page_resp = self.test_case.kw_joyhub_product_attr_data_page_get(page_no=1, page_size=10)
|
||||||
|
assert page_resp.get("code") == 0, f"获取分页失败,code={page_resp.get('code')}, msg={page_resp.get('msg')}"
|
||||||
|
assert page_resp.get("data", {}).get("list"), "没有找到可用的产品属性值数据"
|
||||||
|
product_attr_data_id = page_resp["data"]["list"][0].get("id")
|
||||||
|
assert product_attr_data_id, "产品属性值ID为空"
|
||||||
|
|
||||||
|
with allure.step("2. 调用获取详情接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_product_attr_data_get_get(product_attr_data_id=product_attr_data_id)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert "id" in resp["data"], "响应中缺少id字段"
|
||||||
|
assert resp["data"]["id"] == product_attr_data_id, "返回的ID与请求的ID不一致"
|
||||||
|
assert "attrValue" in resp["data"], "响应中缺少attrValue字段"
|
||||||
|
assert isinstance(resp["data"]["attrValue"], str), "attrValue字段不是字符串类型"
|
||||||
|
logging.info("获得产品属性值详情验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证创建和更新产品属性值")
|
||||||
|
@allure.title("测试创建和更新产品属性值接口")
|
||||||
|
def test_joyhub_product_attr_data_create_and_update(self):
|
||||||
|
"""测试创建和更新产品属性值接口"""
|
||||||
|
# 如果没有创建的产品属性ID,则使用已有产品属性ID
|
||||||
|
product_attr_type_id = TestProductAttrManage.product_attr_type_id
|
||||||
|
if not product_attr_type_id:
|
||||||
|
with allure.step("获取已有产品属性ID"):
|
||||||
|
page_resp = self.test_case.kw_joyhub_product_attr_type_page_get(page_no=1, page_size=10)
|
||||||
|
assert page_resp.get("code") == 0, f"获取分页失败,code={page_resp.get('code')}, msg={page_resp.get('msg')}"
|
||||||
|
assert page_resp.get("data", {}).get("list"), "没有找到可用的产品属性数据"
|
||||||
|
product_attr_type_id = page_resp["data"]["list"][0].get("id")
|
||||||
|
|
||||||
|
with allure.step("1. 创建产品属性值"):
|
||||||
|
timestamp = int(time.time())
|
||||||
|
create_params = {
|
||||||
|
"product_attr_type_id": product_attr_type_id,
|
||||||
|
"attr_value": f"测试属性值_{timestamp}",
|
||||||
|
"color": ["#FF0000", "#00FF00"]
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(create_params, ensure_ascii=False), name="创建请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
create_resp = self.test_case.kw_joyhub_product_attr_data_create_post(**create_params)
|
||||||
|
allure.attach(json.dumps(create_resp, ensure_ascii=False, indent=2), name="创建响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
assert create_resp is not None, "响应为空"
|
||||||
|
assert "code" in create_resp, "响应中缺少code字段"
|
||||||
|
assert create_resp["code"] == 0, f"创建失败,code={create_resp.get('code')}, msg={create_resp.get('msg')}"
|
||||||
|
assert "data" in create_resp, "响应中缺少data字段"
|
||||||
|
assert isinstance(create_resp["data"], int), "data字段不是整数类型"
|
||||||
|
product_attr_data_id = create_resp["data"]
|
||||||
|
TestProductAttrManage.product_attr_data_id = product_attr_data_id
|
||||||
|
logging.info(f"创建产品属性值成功,ID: {product_attr_data_id}")
|
||||||
|
|
||||||
|
with allure.step("2. 调用更新接口"):
|
||||||
|
timestamp = int(time.time())
|
||||||
|
update_params = {
|
||||||
|
"product_attr_data_id": product_attr_data_id,
|
||||||
|
"product_attr_type_id": product_attr_type_id,
|
||||||
|
"attr_value": f"测试属性值_{timestamp}_updated",
|
||||||
|
"color": ["#0000FF"]
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(update_params, ensure_ascii=False), name="更新请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
update_resp = self.test_case.kw_joyhub_product_attr_data_update_put(**update_params)
|
||||||
|
allure.attach(json.dumps(update_resp, ensure_ascii=False, indent=2), name="更新响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证更新响应"):
|
||||||
|
assert update_resp is not None, "响应为空"
|
||||||
|
assert "code" in update_resp, "响应中缺少code字段"
|
||||||
|
assert update_resp["code"] == 0, f"更新失败,code={update_resp.get('code')}, msg={update_resp.get('msg')}"
|
||||||
|
assert "data" in update_resp, "响应中缺少data字段"
|
||||||
|
assert update_resp["data"] is True, "更新产品属性值失败"
|
||||||
|
logging.info("创建并更新产品属性值验证通过")
|
||||||
|
|
||||||
|
# ============ 删除测试用例 ============
|
||||||
|
|
||||||
|
@allure.story("验证删除产品属性值")
|
||||||
|
@allure.title("测试删除产品属性值接口")
|
||||||
|
def test_joyhub_product_attr_data_delete_delete(self):
|
||||||
|
"""测试删除产品属性值接口"""
|
||||||
|
if not TestProductAttrManage.product_attr_data_id:
|
||||||
|
pytest.skip("没有可删除的产品属性值数据")
|
||||||
|
|
||||||
|
with allure.step("1. 调用删除接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_product_attr_data_delete_delete(product_attr_data_id=TestProductAttrManage.product_attr_data_id)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("2. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"删除失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert resp["data"] is True, "删除产品属性值失败"
|
||||||
|
logging.info("删除产品属性值验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证删除产品属性")
|
||||||
|
@allure.title("测试删除产品属性接口")
|
||||||
|
def test_joyhub_product_attr_type_delete_delete(self):
|
||||||
|
"""测试删除产品属性接口"""
|
||||||
|
if not TestProductAttrManage.product_attr_type_id:
|
||||||
|
pytest.skip("没有可删除的产品属性数据")
|
||||||
|
|
||||||
|
with allure.step("1. 先将产品属性状态改为停用"):
|
||||||
|
status_resp = self.test_case.kw_joyhub_product_attr_type_change_status_put(
|
||||||
|
product_attr_type_id=TestProductAttrManage.product_attr_type_id,
|
||||||
|
status=2
|
||||||
|
)
|
||||||
|
assert status_resp.get("code") == 0, f"修改状态失败,code={status_resp.get('code')}, msg={status_resp.get('msg')}"
|
||||||
|
|
||||||
|
with allure.step("2. 调用删除接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_product_attr_type_delete_delete(product_attr_type_id=TestProductAttrManage.product_attr_type_id)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"删除失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert resp["data"] is True, "删除产品属性失败"
|
||||||
|
logging.info("删除产品属性验证通过")
|
||||||
201
dulizhan/test_case/TestCase/接口/JoyHub/Joyhub_ProductCate.py
Normal file
201
dulizhan/test_case/TestCase/接口/JoyHub/Joyhub_ProductCate.py
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
产品分类管理接口测试用例
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import pytest
|
||||||
|
import allure
|
||||||
|
import logging
|
||||||
|
import time
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from dulizhan.library.BusinessKw.JoyHub.ProductCateManage import ProductCateManage
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("管理后台 - 产品分类管理模块")
|
||||||
|
class TestProductCateManage:
|
||||||
|
product_cate_id = None
|
||||||
|
token_set = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setup_class(cls):
|
||||||
|
"""在整个测试类开始时登录一次,所有测试用例共享token"""
|
||||||
|
logging.info("=============================================")
|
||||||
|
logging.info("=========== 开始登录,获取Token ============")
|
||||||
|
logging.info("=============================================")
|
||||||
|
|
||||||
|
cls.test_case = ProductCateManage()
|
||||||
|
username = "joytest"
|
||||||
|
password = "Zhou1599"
|
||||||
|
|
||||||
|
cls.test_case._clear_user_fingerprint(username)
|
||||||
|
|
||||||
|
url = 'https://joyhub-website-manager-api-test.best-envision.com/admin-api/system/auth/login-dev'
|
||||||
|
payload = {'username': username, 'password': password}
|
||||||
|
headers = {'Content-Type': 'application/json', 'tenant-id': '126'}
|
||||||
|
|
||||||
|
response = requests.post(url, json=payload, headers=headers, verify=False, timeout=10)
|
||||||
|
login_response = response.json()
|
||||||
|
|
||||||
|
if login_response and login_response.get('code') == 0:
|
||||||
|
token = login_response.get('data', {}).get('accessToken', '')
|
||||||
|
cls.test_case.set_joyhub_token(token)
|
||||||
|
cls.token_set = True
|
||||||
|
logging.info("登录成功,Token已设置")
|
||||||
|
else:
|
||||||
|
logging.error(f"登录失败: {login_response}")
|
||||||
|
|
||||||
|
@allure.story("验证登录接口")
|
||||||
|
@allure.title("测试登录接口")
|
||||||
|
def test_joyhub_login_post(self):
|
||||||
|
"""测试登录接口"""
|
||||||
|
assert TestProductCateManage.token_set is True, "登录失败,未获取到token"
|
||||||
|
logging.info("登录验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证获得产品分类分页")
|
||||||
|
@allure.title("测试获得产品分类分页接口")
|
||||||
|
def test_joyhub_product_cate_page_get(self):
|
||||||
|
"""测试获得产品分类分页接口"""
|
||||||
|
with allure.step("1. 调用分页接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_product_cate_page_get(page_no=1, page_size=10)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("2. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert "list" in resp["data"], "响应中缺少list字段"
|
||||||
|
assert isinstance(resp["data"]["list"], list), "list字段不是列表类型"
|
||||||
|
logging.info("获得产品分类分页验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证获得产品分类详情")
|
||||||
|
@allure.title("测试获得产品分类详情接口")
|
||||||
|
def test_joyhub_product_cate_get_get(self):
|
||||||
|
"""测试获得产品分类详情接口"""
|
||||||
|
with allure.step("1. 从分页获取现有产品分类ID"):
|
||||||
|
page_resp = self.test_case.kw_joyhub_product_cate_page_get(page_no=1, page_size=10)
|
||||||
|
assert page_resp.get("code") == 0, f"获取分页失败,code={page_resp.get('code')}, msg={page_resp.get('msg')}"
|
||||||
|
assert page_resp.get("data", {}).get("list"), "没有找到可用的产品分类数据"
|
||||||
|
product_cate_id = page_resp["data"]["list"][0].get("id")
|
||||||
|
assert product_cate_id, "产品分类ID为空"
|
||||||
|
|
||||||
|
with allure.step("2. 调用获取详情接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_product_cate_get_get(product_cate_id=product_cate_id)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert "id" in resp["data"], "响应中缺少id字段"
|
||||||
|
assert resp["data"]["id"] == product_cate_id, "返回的ID与请求的ID不一致"
|
||||||
|
assert "cateName" in resp["data"], "响应中缺少cateName字段"
|
||||||
|
assert isinstance(resp["data"]["cateName"], str), "cateName字段不是字符串类型"
|
||||||
|
logging.info("获得产品分类详情验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证创建和更新产品分类")
|
||||||
|
@allure.title("测试创建和更新产品分类接口")
|
||||||
|
def test_joyhub_product_cate_create_and_update(self):
|
||||||
|
"""测试创建和更新产品分类接口"""
|
||||||
|
with allure.step("1. 创建产品分类"):
|
||||||
|
timestamp = int(time.time())
|
||||||
|
create_params = {
|
||||||
|
"cate_name": f"测试产品分类_{timestamp}",
|
||||||
|
"cate_type": 1,
|
||||||
|
"status": 1,
|
||||||
|
"rank_num": 1
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(create_params, ensure_ascii=False), name="创建请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
create_resp = self.test_case.kw_joyhub_product_cate_create_post(**create_params)
|
||||||
|
allure.attach(json.dumps(create_resp, ensure_ascii=False, indent=2), name="创建响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
assert create_resp is not None, "响应为空"
|
||||||
|
assert "code" in create_resp, "响应中缺少code字段"
|
||||||
|
assert create_resp["code"] == 0, f"创建失败,code={create_resp.get('code')}, msg={create_resp.get('msg')}"
|
||||||
|
assert "data" in create_resp, "响应中缺少data字段"
|
||||||
|
assert isinstance(create_resp["data"], int), "data字段不是整数类型"
|
||||||
|
product_cate_id = create_resp["data"]
|
||||||
|
TestProductCateManage.product_cate_id = product_cate_id
|
||||||
|
logging.info(f"创建产品分类成功,ID: {product_cate_id}")
|
||||||
|
|
||||||
|
with allure.step("2. 调用更新接口"):
|
||||||
|
timestamp = int(time.time())
|
||||||
|
update_params = {
|
||||||
|
"product_cate_id": product_cate_id,
|
||||||
|
"cate_name": f"测试产品分类_{timestamp}_updated",
|
||||||
|
"cate_type": 1,
|
||||||
|
"status": 2,
|
||||||
|
"rank_num": 2
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(update_params, ensure_ascii=False), name="更新请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
update_resp = self.test_case.kw_joyhub_product_cate_update_put(**update_params)
|
||||||
|
allure.attach(json.dumps(update_resp, ensure_ascii=False, indent=2), name="更新响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证更新响应"):
|
||||||
|
assert update_resp is not None, "响应为空"
|
||||||
|
assert "code" in update_resp, "响应中缺少code字段"
|
||||||
|
assert update_resp["code"] == 0, f"更新失败,code={update_resp.get('code')}, msg={update_resp.get('msg')}"
|
||||||
|
assert "data" in update_resp, "响应中缺少data字段"
|
||||||
|
assert update_resp["data"] is True, "更新产品分类失败"
|
||||||
|
logging.info("创建并更新产品分类验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证修改产品分类状态")
|
||||||
|
@allure.title("测试修改产品分类状态接口")
|
||||||
|
def test_joyhub_product_cate_change_status_put(self):
|
||||||
|
"""测试修改产品分类状态接口"""
|
||||||
|
if not TestProductCateManage.product_cate_id:
|
||||||
|
pytest.skip("没有可修改状态的产品分类数据")
|
||||||
|
|
||||||
|
with allure.step("1. 调用修改状态接口(停用)"):
|
||||||
|
resp = self.test_case.kw_joyhub_product_cate_change_status_put(
|
||||||
|
product_cate_id=TestProductCateManage.product_cate_id,
|
||||||
|
status=2
|
||||||
|
)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("2. 验证停用响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"修改状态失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert resp["data"] is True, "修改产品分类状态失败"
|
||||||
|
|
||||||
|
with allure.step("3. 调用修改状态接口(启用)"):
|
||||||
|
resp = self.test_case.kw_joyhub_product_cate_change_status_put(
|
||||||
|
product_cate_id=TestProductCateManage.product_cate_id,
|
||||||
|
status=1
|
||||||
|
)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("4. 验证启用响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"修改状态失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert resp["data"] is True, "修改产品分类状态失败"
|
||||||
|
logging.info("修改产品分类状态验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证删除产品分类")
|
||||||
|
@allure.title("测试删除产品分类接口")
|
||||||
|
def test_joyhub_product_cate_delete_delete(self):
|
||||||
|
"""测试删除产品分类接口"""
|
||||||
|
if not TestProductCateManage.product_cate_id:
|
||||||
|
pytest.skip("没有可删除的产品分类数据")
|
||||||
|
|
||||||
|
with allure.step("1. 调用删除接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_product_cate_delete_delete(product_cate_id=TestProductCateManage.product_cate_id)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("2. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"删除失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert resp["data"] is True, "删除产品分类失败"
|
||||||
|
logging.info("删除产品分类验证通过")
|
||||||
@@ -0,0 +1,279 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
支付页产品推荐接口测试用例
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import pytest
|
||||||
|
import allure
|
||||||
|
import logging
|
||||||
|
import requests
|
||||||
|
|
||||||
|
from dulizhan.library.BusinessKw.JoyHub.ProductManage import ProductManage
|
||||||
|
from dulizhan.library.BusinessKw.JoyHub.ProductPaymentRecommendManage import ProductPaymentRecommendManage
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("管理后台 - 支付页产品推荐模块")
|
||||||
|
class TestProductPaymentRecommendManage:
|
||||||
|
product_id = None
|
||||||
|
recommend_id = None
|
||||||
|
batch_recommend_id = None
|
||||||
|
token = None
|
||||||
|
token_set = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setup_class(cls):
|
||||||
|
"""在整个测试类开始时登录一次,所有测试用例共享token"""
|
||||||
|
logging.info("=============================================")
|
||||||
|
logging.info("=========== 开始登录,获取Token ============")
|
||||||
|
logging.info("=============================================")
|
||||||
|
|
||||||
|
cls.test_case = ProductPaymentRecommendManage()
|
||||||
|
username = "joytest"
|
||||||
|
password = "Zhou1599"
|
||||||
|
|
||||||
|
cls.test_case._clear_user_fingerprint(username)
|
||||||
|
|
||||||
|
url = 'https://joyhub-website-manager-api-test.best-envision.com/admin-api/system/auth/login-dev'
|
||||||
|
payload = {'username': username, 'password': password}
|
||||||
|
headers = {'Content-Type': 'application/json', 'tenant-id': '126'}
|
||||||
|
|
||||||
|
response = requests.post(url, json=payload, headers=headers, verify=False, timeout=10)
|
||||||
|
login_response = response.json()
|
||||||
|
|
||||||
|
if login_response and login_response.get('code') == 0:
|
||||||
|
token = login_response.get('data', {}).get('accessToken', '')
|
||||||
|
cls.token = token
|
||||||
|
cls.test_case.set_joyhub_token(token)
|
||||||
|
cls.token_set = True
|
||||||
|
logging.info("登录成功,Token已设置")
|
||||||
|
|
||||||
|
recommend_page_resp = cls.test_case.kw_joyhub_product_payment_recommend_page_get(page_no=1, page_size=999)
|
||||||
|
recommended_product_ids = set()
|
||||||
|
if recommend_page_resp.get('code') == 0 and recommend_page_resp.get('data', {}).get('list'):
|
||||||
|
recommended_product_ids = {
|
||||||
|
item.get('productId') for item in recommend_page_resp['data']['list'] if item.get('productId')
|
||||||
|
}
|
||||||
|
|
||||||
|
product_manage = ProductManage()
|
||||||
|
product_manage.set_joyhub_token(token)
|
||||||
|
product_page_resp = product_manage.kw_joyhub_product_page_get(page_no=1, page_size=50)
|
||||||
|
if product_page_resp.get('code') == 0 and product_page_resp.get('data', {}).get('list'):
|
||||||
|
for product_item in product_page_resp['data']['list']:
|
||||||
|
product_id = product_item.get('id')
|
||||||
|
if product_id and product_id not in recommended_product_ids:
|
||||||
|
cls.product_id = product_id
|
||||||
|
break
|
||||||
|
logging.info(f"获取到未推荐产品ID: {cls.product_id}")
|
||||||
|
else:
|
||||||
|
logging.error(f"登录失败: {login_response}")
|
||||||
|
|
||||||
|
@allure.story("验证登录接口")
|
||||||
|
@allure.title("测试登录接口")
|
||||||
|
def test_joyhub_login_post(self):
|
||||||
|
"""测试登录接口"""
|
||||||
|
assert TestProductPaymentRecommendManage.token_set is True, "登录失败,未获取到token"
|
||||||
|
logging.info("登录验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证管理后台获得支付页产品推荐分页")
|
||||||
|
@allure.title("测试管理后台获得支付页产品推荐分页接口")
|
||||||
|
def test_joyhub_product_payment_recommend_page_get(self):
|
||||||
|
"""测试管理后台获得支付页产品推荐分页接口"""
|
||||||
|
with allure.step("1. 准备请求参数"):
|
||||||
|
self.test_case.set_joyhub_token(TestProductPaymentRecommendManage.token)
|
||||||
|
params = {
|
||||||
|
"page_no": 1,
|
||||||
|
"page_size": 10,
|
||||||
|
"recommendStatus": 1
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用分页接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_product_payment_recommend_page_get(**params)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert "list" in resp["data"], "响应中缺少list字段"
|
||||||
|
assert isinstance(resp["data"]["list"], list), "list字段不是列表类型"
|
||||||
|
if "total" in resp["data"]:
|
||||||
|
assert isinstance(resp["data"]["total"], int), "total字段不是整数类型"
|
||||||
|
logging.info("管理后台获得支付页产品推荐分页验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证创建支付页产品推荐")
|
||||||
|
@allure.title("测试创建支付页产品推荐接口")
|
||||||
|
def test_joyhub_product_payment_recommend_create_post(self):
|
||||||
|
"""测试创建支付页产品推荐接口"""
|
||||||
|
if not TestProductPaymentRecommendManage.product_id:
|
||||||
|
pytest.skip("没有可用于创建支付页产品推荐的产品数据")
|
||||||
|
|
||||||
|
with allure.step("1. 准备请求参数"):
|
||||||
|
params = {
|
||||||
|
"product_ids": [TestProductPaymentRecommendManage.product_id]
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用创建接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_product_payment_recommend_create_post(**params)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"创建失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert isinstance(resp["data"], int), "data字段不是整数类型"
|
||||||
|
TestProductPaymentRecommendManage.recommend_id = resp["data"]
|
||||||
|
logging.info(f"创建支付页产品推荐成功,ID: {resp['data']}")
|
||||||
|
|
||||||
|
@allure.story("验证修改支付页产品推荐排序号")
|
||||||
|
@allure.title("测试修改支付页产品推荐排序号接口")
|
||||||
|
def test_joyhub_product_payment_recommend_change_rank_num_put(self):
|
||||||
|
"""测试修改支付页产品推荐排序号接口"""
|
||||||
|
if not TestProductPaymentRecommendManage.recommend_id:
|
||||||
|
pytest.skip("没有可修改排序号的支付页产品推荐数据")
|
||||||
|
|
||||||
|
with allure.step("1. 准备请求参数"):
|
||||||
|
params = {
|
||||||
|
"recommend_id": TestProductPaymentRecommendManage.recommend_id,
|
||||||
|
"rank_num": 1
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用修改排序号接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_product_payment_recommend_change_rank_num_put(**params)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"修改排序号失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert resp["data"] is True, "修改支付页产品推荐排序号失败"
|
||||||
|
logging.info("修改支付页产品推荐排序号验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证修改支付页产品推荐状态")
|
||||||
|
@allure.title("测试修改支付页产品推荐状态接口")
|
||||||
|
def test_joyhub_product_payment_recommend_change_status_put(self):
|
||||||
|
"""测试修改支付页产品推荐状态接口"""
|
||||||
|
if not TestProductPaymentRecommendManage.recommend_id:
|
||||||
|
pytest.skip("没有可修改状态的支付页产品推荐数据")
|
||||||
|
|
||||||
|
with allure.step("1. 准备请求参数"):
|
||||||
|
params = {
|
||||||
|
"recommend_id": TestProductPaymentRecommendManage.recommend_id,
|
||||||
|
"recommend_status": 2
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用修改状态接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_product_payment_recommend_change_status_put(**params)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"修改状态失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert resp["data"] is True, "修改支付页产品推荐状态失败"
|
||||||
|
logging.info("修改支付页产品推荐状态验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证删除支付页产品推荐")
|
||||||
|
@allure.title("测试删除支付页产品推荐接口")
|
||||||
|
def test_joyhub_product_payment_recommend_delete_delete(self):
|
||||||
|
"""测试删除支付页产品推荐接口"""
|
||||||
|
if not TestProductPaymentRecommendManage.recommend_id:
|
||||||
|
pytest.skip("没有可删除的支付页产品推荐数据")
|
||||||
|
|
||||||
|
with allure.step("1. 调用删除接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_product_payment_recommend_delete_delete(
|
||||||
|
recommend_id=TestProductPaymentRecommendManage.recommend_id
|
||||||
|
)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("2. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"删除失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert resp["data"] is True, "删除支付页产品推荐失败"
|
||||||
|
TestProductPaymentRecommendManage.recommend_id = None
|
||||||
|
logging.info("删除支付页产品推荐验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证批量删除支付页产品推荐")
|
||||||
|
@allure.title("测试批量删除支付页产品推荐接口")
|
||||||
|
def test_joyhub_product_payment_recommend_delete_list_delete(self):
|
||||||
|
"""测试批量删除支付页产品推荐接口"""
|
||||||
|
if not TestProductPaymentRecommendManage.product_id:
|
||||||
|
pytest.skip("没有可用于创建支付页产品推荐的产品数据")
|
||||||
|
|
||||||
|
with allure.step("1. 创建一条用于批量删除的支付页产品推荐"):
|
||||||
|
create_resp = self.test_case.kw_joyhub_product_payment_recommend_create_post(
|
||||||
|
product_ids=[TestProductPaymentRecommendManage.product_id]
|
||||||
|
)
|
||||||
|
allure.attach(json.dumps(create_resp, ensure_ascii=False, indent=2), name="创建响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
assert create_resp is not None, "响应为空"
|
||||||
|
assert "code" in create_resp, "响应中缺少code字段"
|
||||||
|
assert create_resp["code"] == 0, f"创建失败,code={create_resp.get('code')}, msg={create_resp.get('msg')}"
|
||||||
|
assert "data" in create_resp, "响应中缺少data字段"
|
||||||
|
assert isinstance(create_resp["data"], int), "data字段不是整数类型"
|
||||||
|
TestProductPaymentRecommendManage.batch_recommend_id = create_resp["data"]
|
||||||
|
|
||||||
|
with allure.step("2. 将支付页产品推荐状态改为停用"):
|
||||||
|
status_resp = self.test_case.kw_joyhub_product_payment_recommend_change_status_put(
|
||||||
|
recommend_id=TestProductPaymentRecommendManage.batch_recommend_id,
|
||||||
|
recommend_status=2
|
||||||
|
)
|
||||||
|
allure.attach(json.dumps(status_resp, ensure_ascii=False, indent=2), name="修改状态响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
assert status_resp is not None, "响应为空"
|
||||||
|
assert "code" in status_resp, "响应中缺少code字段"
|
||||||
|
assert status_resp["code"] == 0, f"修改状态失败,code={status_resp.get('code')}, msg={status_resp.get('msg')}"
|
||||||
|
assert status_resp.get("data") is True, "修改支付页产品推荐状态失败"
|
||||||
|
|
||||||
|
with allure.step("3. 调用批量删除接口"):
|
||||||
|
params = {
|
||||||
|
"ids": [TestProductPaymentRecommendManage.batch_recommend_id]
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
resp = self.test_case.kw_joyhub_product_payment_recommend_delete_list_delete(**params)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("4. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"批量删除失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert resp["data"] is True, "批量删除支付页产品推荐失败"
|
||||||
|
TestProductPaymentRecommendManage.batch_recommend_id = None
|
||||||
|
logging.info("批量删除支付页产品推荐验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证C端获得支付页产品推荐分页")
|
||||||
|
@allure.title("测试C端获得支付页产品推荐分页接口")
|
||||||
|
def test_joyhub_web_product_payment_recommend_page_get(self):
|
||||||
|
"""测试获得支付页产品推荐分页接口"""
|
||||||
|
with allure.step("1. 准备请求参数"):
|
||||||
|
self.test_case.set_joyhub_token(None)
|
||||||
|
params = {
|
||||||
|
"page_no": 1,
|
||||||
|
"page_size": 10
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用分页接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_web_product_payment_recommend_page_get(**params)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert "list" in resp["data"], "响应中缺少list字段"
|
||||||
|
assert isinstance(resp["data"]["list"], list), "list字段不是列表类型"
|
||||||
|
if "total" in resp["data"]:
|
||||||
|
assert isinstance(resp["data"]["total"], int), "total字段不是整数类型"
|
||||||
|
logging.info("获得支付页产品推荐分页验证通过")
|
||||||
49
dulizhan/test_case/TestCase/接口/JoyHubC/JoyhubC_AppVersion.py
Normal file
49
dulizhan/test_case/TestCase/接口/JoyHubC/JoyhubC_AppVersion.py
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
JoyHub C端APP版本接口测试用例
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import allure
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from dulizhan.library.BusinessKw.JoyHubC.AppVersionManage import JoyHubCAppVersionManage
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("C端 - APP版本模块")
|
||||||
|
class TestJoyHubCAppVersion:
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setup_class(cls):
|
||||||
|
"""在整个测试类开始时初始化C端APP版本业务关键字"""
|
||||||
|
logging.info("=============================================")
|
||||||
|
logging.info("=========== 开始JoyHub C端APP版本接口测试 =========")
|
||||||
|
logging.info("=============================================")
|
||||||
|
cls.test_case = JoyHubCAppVersionManage()
|
||||||
|
|
||||||
|
@allure.story("验证C端获取APP版本列表")
|
||||||
|
@allure.title("测试C端获取APP版本列表接口")
|
||||||
|
def test_joyhub_c_web_appversion_page_get(self):
|
||||||
|
"""测试C端获取APP版本列表接口"""
|
||||||
|
with allure.step("1. 准备请求参数"):
|
||||||
|
params = {
|
||||||
|
"pageNo": 1,
|
||||||
|
"pageSize": 10
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用获取APP版本列表接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_c_web_appversion_page_get(**params)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert "list" in resp["data"], "响应中缺少list字段"
|
||||||
|
assert isinstance(resp["data"]["list"], list), "list字段不是列表类型"
|
||||||
|
if "total" in resp["data"]:
|
||||||
|
assert isinstance(resp["data"]["total"], int), "total字段不是整数类型"
|
||||||
|
logging.info("C端获取APP版本列表接口验证通过")
|
||||||
81
dulizhan/test_case/TestCase/接口/JoyHubC/JoyhubC_Banner.py
Normal file
81
dulizhan/test_case/TestCase/接口/JoyHubC/JoyhubC_Banner.py
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
JoyHub C端Banner信息接口测试用例
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import allure
|
||||||
|
import logging
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from dulizhan.library.BusinessKw.JoyHubC.BannerManage import JoyHubCBannerManage
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("C端 - Banner信息模块")
|
||||||
|
class TestJoyHubCBanner:
|
||||||
|
banner_id = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setup_class(cls):
|
||||||
|
"""在整个测试类开始时初始化C端Banner业务关键字"""
|
||||||
|
logging.info("=============================================")
|
||||||
|
logging.info("=========== 开始JoyHub C端Banner信息接口测试 =========")
|
||||||
|
logging.info("=============================================")
|
||||||
|
cls.test_case = JoyHubCBannerManage()
|
||||||
|
|
||||||
|
@allure.story("验证C端获得Banner管理分页")
|
||||||
|
@allure.title("测试C端获得Banner管理分页接口")
|
||||||
|
def test_joyhub_c_banner_page_get(self):
|
||||||
|
"""测试C端获得Banner管理分页接口"""
|
||||||
|
with allure.step("1. 准备请求参数"):
|
||||||
|
params = {
|
||||||
|
"platform": 1,
|
||||||
|
"lang": "en",
|
||||||
|
"pageNo": 1,
|
||||||
|
"pageSize": 10
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用获得Banner管理分页接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_c_banner_page_get(**params)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert "list" in resp["data"], "响应中缺少list字段"
|
||||||
|
assert isinstance(resp["data"]["list"], list), "list字段不是列表类型"
|
||||||
|
if "total" in resp["data"]:
|
||||||
|
assert isinstance(resp["data"]["total"], int), "total字段不是整数类型"
|
||||||
|
if resp["data"]["list"]:
|
||||||
|
TestJoyHubCBanner.banner_id = resp["data"]["list"][0].get("id")
|
||||||
|
logging.info("C端获得Banner管理分页接口验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证C端获得Banner管理")
|
||||||
|
@allure.title("测试C端获得Banner管理接口")
|
||||||
|
def test_joyhub_c_banner_get_get(self):
|
||||||
|
"""测试C端获得Banner管理接口"""
|
||||||
|
if not TestJoyHubCBanner.banner_id:
|
||||||
|
pytest.skip("没有可用于查询详情的Banner数据")
|
||||||
|
|
||||||
|
with allure.step("1. 准备请求参数"):
|
||||||
|
params = {
|
||||||
|
"id": TestJoyHubCBanner.banner_id
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用获得Banner管理接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_c_banner_get_get(**params)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert resp["data"] is not None, "data字段为空"
|
||||||
|
assert resp["data"].get("id") == TestJoyHubCBanner.banner_id, "返回的Banner ID与请求ID不一致"
|
||||||
|
logging.info("C端获得Banner管理接口验证通过")
|
||||||
110
dulizhan/test_case/TestCase/接口/JoyHubC/JoyhubC_Blog.py
Normal file
110
dulizhan/test_case/TestCase/接口/JoyHubC/JoyhubC_Blog.py
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
JoyHub C端blog信息接口测试用例
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import allure
|
||||||
|
import logging
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from dulizhan.library.BusinessKw.JoyHubC.BlogManage import JoyHubCBlogManage
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("C端 - blog信息模块")
|
||||||
|
class TestJoyHubCBlog:
|
||||||
|
blog_id = None
|
||||||
|
blog_cate_id = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setup_class(cls):
|
||||||
|
"""在整个测试类开始时初始化C端blog信息业务关键字"""
|
||||||
|
logging.info("=============================================")
|
||||||
|
logging.info("=========== 开始JoyHub C端blog信息接口测试 =========")
|
||||||
|
logging.info("=============================================")
|
||||||
|
cls.test_case = JoyHubCBlogManage()
|
||||||
|
|
||||||
|
@allure.story("验证C端获得blog管理分页")
|
||||||
|
@allure.title("测试C端获得blog管理分页接口")
|
||||||
|
def test_joyhub_c_blog_page_get(self):
|
||||||
|
"""测试C端获得blog管理分页接口"""
|
||||||
|
with allure.step("1. 准备请求参数"):
|
||||||
|
params = {
|
||||||
|
"pageNo": 1,
|
||||||
|
"pageSize": 10
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用获得blog管理分页接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_c_blog_page_get(**params)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert "list" in resp["data"], "响应中缺少list字段"
|
||||||
|
assert isinstance(resp["data"]["list"], list), "list字段不是列表类型"
|
||||||
|
if "total" in resp["data"]:
|
||||||
|
assert isinstance(resp["data"]["total"], int), "total字段不是整数类型"
|
||||||
|
if resp["data"]["list"]:
|
||||||
|
first_blog = resp["data"]["list"][0]
|
||||||
|
TestJoyHubCBlog.blog_id = first_blog.get("id")
|
||||||
|
TestJoyHubCBlog.blog_cate_id = first_blog.get("cateId")
|
||||||
|
logging.info("C端获得blog管理分页接口验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证C端获得blog详情")
|
||||||
|
@allure.title("测试C端获得blog详情接口")
|
||||||
|
def test_joyhub_c_blog_get_detail_get(self):
|
||||||
|
"""测试C端获得blog详情接口"""
|
||||||
|
if not TestJoyHubCBlog.blog_id:
|
||||||
|
pytest.skip("没有可用于查询详情的blog数据")
|
||||||
|
|
||||||
|
with allure.step("1. 准备请求参数"):
|
||||||
|
params = {
|
||||||
|
"id": TestJoyHubCBlog.blog_id
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用获得blog详情接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_c_blog_get_detail_get(**params)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert resp["data"] is not None, "data字段为空"
|
||||||
|
assert resp["data"].get("id") == TestJoyHubCBlog.blog_id, "返回的blog ID与请求ID不一致"
|
||||||
|
logging.info("C端获得blog详情接口验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证C端获得blog下一条")
|
||||||
|
@allure.title("测试C端获得blog下一条接口")
|
||||||
|
def test_joyhub_c_blog_get_next_get(self):
|
||||||
|
"""测试C端获得blog下一条接口"""
|
||||||
|
if not TestJoyHubCBlog.blog_id:
|
||||||
|
pytest.skip("没有可用于查询下一条的blog数据")
|
||||||
|
|
||||||
|
with allure.step("1. 准备请求参数"):
|
||||||
|
params = {
|
||||||
|
"id": TestJoyHubCBlog.blog_id
|
||||||
|
}
|
||||||
|
if TestJoyHubCBlog.blog_cate_id:
|
||||||
|
params["cateId"] = TestJoyHubCBlog.blog_cate_id
|
||||||
|
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用获得blog下一条接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_c_blog_get_next_get(**params)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
if resp["data"] is not None:
|
||||||
|
assert isinstance(resp["data"], dict), "data字段不是字典类型"
|
||||||
|
logging.info("C端获得blog下一条接口验证通过")
|
||||||
39
dulizhan/test_case/TestCase/接口/JoyHubC/JoyhubC_BlogCate.py
Normal file
39
dulizhan/test_case/TestCase/接口/JoyHubC/JoyhubC_BlogCate.py
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
JoyHub C端blog分类接口测试用例
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import allure
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from dulizhan.library.BusinessKw.JoyHubC.BlogCateManage import JoyHubCBlogCateManage
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("C端 - blog分类模块")
|
||||||
|
class TestJoyHubCBlogCate:
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setup_class(cls):
|
||||||
|
"""在整个测试类开始时初始化C端blog分类业务关键字"""
|
||||||
|
logging.info("=============================================")
|
||||||
|
logging.info("=========== 开始JoyHub C端blog分类接口测试 =========")
|
||||||
|
logging.info("=============================================")
|
||||||
|
cls.test_case = JoyHubCBlogCateManage()
|
||||||
|
|
||||||
|
@allure.story("验证C端获得blog分类列表")
|
||||||
|
@allure.title("测试C端获得blog分类列表接口")
|
||||||
|
def test_joyhub_c_blog_cate_list_get(self):
|
||||||
|
"""测试C端获得blog分类列表接口"""
|
||||||
|
with allure.step("1. 调用获得blog分类列表接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_c_blog_cate_list_get()
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("2. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert isinstance(resp["data"], list), "data字段不是列表类型"
|
||||||
|
logging.info("C端获得blog分类列表接口验证通过")
|
||||||
@@ -0,0 +1,52 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
JoyHub C端合作联系接口测试用例
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import time
|
||||||
|
import allure
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from dulizhan.library.BusinessKw.JoyHubC.CooperationManage import JoyHubCCooperationManage
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("C端 - 合作联系模块")
|
||||||
|
class TestJoyHubCCooperation:
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setup_class(cls):
|
||||||
|
"""在整个测试类开始时初始化C端合作联系业务关键字"""
|
||||||
|
logging.info("=============================================")
|
||||||
|
logging.info("=========== 开始JoyHub C端合作联系接口测试 =========")
|
||||||
|
logging.info("=============================================")
|
||||||
|
cls.test_case = JoyHubCCooperationManage()
|
||||||
|
|
||||||
|
@allure.story("验证C端提交合作联系信息")
|
||||||
|
@allure.title("测试C端提交合作联系信息接口")
|
||||||
|
def test_joyhub_c_cooperation_create_post(self):
|
||||||
|
"""测试C端提交合作联系信息接口"""
|
||||||
|
with allure.step("1. 准备请求参数"):
|
||||||
|
timestamp = int(time.time())
|
||||||
|
params = {
|
||||||
|
"name": "Auto Test",
|
||||||
|
"email": f"cooperation_{timestamp}@example.com",
|
||||||
|
"address": "Auto Test Company",
|
||||||
|
"cooperationType": "business",
|
||||||
|
"cooperationDetail": "Automation test cooperation detail",
|
||||||
|
"lang": "en"
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用提交合作联系信息接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_c_cooperation_create_post(**params)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert resp["data"] is not None, "data字段为空"
|
||||||
|
logging.info("C端提交合作联系信息接口验证通过")
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
JoyHub C端二维码访问统计接口测试用例
|
||||||
|
"""
|
||||||
|
import os
|
||||||
|
import json
|
||||||
|
import allure
|
||||||
|
import logging
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from dulizhan.library.BusinessKw.JoyHubC.DownloadQrcodeManage import JoyHubCDownloadQrcodeManage
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skip(reason="当前环境未配置可用二维码测试数据,暂时跳过")
|
||||||
|
@allure.feature("C端 - 二维码访问统计模块")
|
||||||
|
class TestJoyHubCDownloadQrcode:
|
||||||
|
qrcode_code = os.environ.get("JOYHUB_C_QRCODE_CODE", "ABC123")
|
||||||
|
qrcode_exists = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setup_class(cls):
|
||||||
|
"""在整个测试类开始时初始化C端二维码访问统计业务关键字"""
|
||||||
|
logging.info("=============================================")
|
||||||
|
logging.info("=========== 开始JoyHub C端二维码访问统计接口测试 =========")
|
||||||
|
logging.info("=============================================")
|
||||||
|
cls.test_case = JoyHubCDownloadQrcodeManage()
|
||||||
|
|
||||||
|
@allure.story("验证C端获取二维码信息")
|
||||||
|
@allure.title("测试C端获取二维码信息接口")
|
||||||
|
def test_joyhub_c_download_qrcode_get_get(self):
|
||||||
|
"""测试C端获取二维码信息接口"""
|
||||||
|
with allure.step("1. 准备请求参数"):
|
||||||
|
params = {
|
||||||
|
"code": TestJoyHubCDownloadQrcode.qrcode_code
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用获取二维码信息接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_c_download_qrcode_get_get(**params)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
if resp["code"] != 0:
|
||||||
|
pytest.skip(f"当前环境未配置可用二维码code,code={resp.get('code')}, msg={resp.get('msg')}")
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
if resp["data"] is None:
|
||||||
|
pytest.skip("当前环境未配置可用二维码code,获取二维码信息返回data为空")
|
||||||
|
TestJoyHubCDownloadQrcode.qrcode_exists = True
|
||||||
|
logging.info("C端获取二维码信息接口验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证C端增加二维码访问/点击次数")
|
||||||
|
@allure.title("测试C端增加二维码访问/点击次数接口")
|
||||||
|
def test_joyhub_c_download_qrcode_increment_post(self):
|
||||||
|
"""测试C端增加二维码访问/点击次数接口"""
|
||||||
|
if not TestJoyHubCDownloadQrcode.qrcode_exists:
|
||||||
|
pytest.skip("没有可用于增加访问/点击次数的二维码数据")
|
||||||
|
|
||||||
|
with allure.step("1. 准备请求参数"):
|
||||||
|
params = {
|
||||||
|
"code": TestJoyHubCDownloadQrcode.qrcode_code,
|
||||||
|
"visitCount": True,
|
||||||
|
"clickCount": True
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用增加二维码访问/点击次数接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_c_download_qrcode_increment_post(**params)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert isinstance(resp["data"], bool), "data字段不是布尔类型"
|
||||||
|
logging.info("C端增加二维码访问/点击次数接口验证通过")
|
||||||
74
dulizhan/test_case/TestCase/接口/JoyHubC/JoyhubC_Faq.py
Normal file
74
dulizhan/test_case/TestCase/接口/JoyHubC/JoyhubC_Faq.py
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
JoyHub C端FAQ接口测试用例
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import allure
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from dulizhan.library.BusinessKw.JoyHubC.FaqManage import JoyHubCFaqManage
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("C端 - FAQ模块")
|
||||||
|
class TestJoyHubCFaq:
|
||||||
|
faq_cate_id = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setup_class(cls):
|
||||||
|
"""在整个测试类开始时初始化C端FAQ业务关键字"""
|
||||||
|
logging.info("=============================================")
|
||||||
|
logging.info("=========== 开始JoyHub C端FAQ接口测试 =========")
|
||||||
|
logging.info("=============================================")
|
||||||
|
cls.test_case = JoyHubCFaqManage()
|
||||||
|
|
||||||
|
@allure.story("验证C端获得FAQ分类树")
|
||||||
|
@allure.title("测试C端获得FAQ分类树接口")
|
||||||
|
def test_joyhub_c_faq_cate_list_get(self):
|
||||||
|
"""测试C端获得FAQ分类树接口"""
|
||||||
|
with allure.step("1. 准备请求参数"):
|
||||||
|
params = {
|
||||||
|
"lang": "en"
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用获得FAQ分类树接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_c_faq_cate_list_get(**params)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert isinstance(resp["data"], list), "data字段不是列表类型"
|
||||||
|
if resp["data"]:
|
||||||
|
TestJoyHubCFaq.faq_cate_id = resp["data"][0].get("id")
|
||||||
|
logging.info("C端获得FAQ分类树接口验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证C端获得FAQ列表")
|
||||||
|
@allure.title("测试C端获得FAQ列表接口")
|
||||||
|
def test_joyhub_c_faq_list_get(self):
|
||||||
|
"""测试C端获得FAQ列表接口"""
|
||||||
|
with allure.step("1. 准备请求参数"):
|
||||||
|
params = {
|
||||||
|
"pageNo": 1,
|
||||||
|
"pageSize": 10,
|
||||||
|
"lang": "en"
|
||||||
|
}
|
||||||
|
if TestJoyHubCFaq.faq_cate_id:
|
||||||
|
params["faqCateId"] = TestJoyHubCFaq.faq_cate_id
|
||||||
|
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用获得FAQ列表接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_c_faq_list_get(**params)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert isinstance(resp["data"], list), "data字段不是列表类型"
|
||||||
|
logging.info("C端获得FAQ列表接口验证通过")
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
JoyHub C端FAQ联系我们接口测试用例
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import time
|
||||||
|
import allure
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from dulizhan.library.BusinessKw.JoyHubC.FaqContactUsManage import JoyHubCFaqContactUsManage
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("C端 - FAQ联系我们模块")
|
||||||
|
class TestJoyHubCFaqContactUs:
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setup_class(cls):
|
||||||
|
"""在整个测试类开始时初始化C端FAQ联系我们业务关键字"""
|
||||||
|
logging.info("=============================================")
|
||||||
|
logging.info("=========== 开始JoyHub C端FAQ联系我们接口测试 =========")
|
||||||
|
logging.info("=============================================")
|
||||||
|
cls.test_case = JoyHubCFaqContactUsManage()
|
||||||
|
|
||||||
|
@allure.story("验证C端提交FAQ联系信息")
|
||||||
|
@allure.title("测试C端提交FAQ联系信息接口")
|
||||||
|
def test_joyhub_c_faq_contact_us_create_post(self):
|
||||||
|
"""测试C端提交FAQ联系信息接口"""
|
||||||
|
with allure.step("1. 准备请求参数"):
|
||||||
|
timestamp = int(time.time())
|
||||||
|
params = {
|
||||||
|
"name": "Auto Test",
|
||||||
|
"email": f"faq_contact_{timestamp}@example.com",
|
||||||
|
"toyOrderNumber": f"TOY{timestamp}",
|
||||||
|
"questionType": "order",
|
||||||
|
"questionDetail": "Automation test FAQ contact detail",
|
||||||
|
"files": [],
|
||||||
|
"lang": "en"
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用提交FAQ联系信息接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_c_faq_contact_us_create_post(**params)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert resp["data"] is not None, "data字段为空"
|
||||||
|
logging.info("C端提交FAQ联系信息接口验证通过")
|
||||||
151
dulizhan/test_case/TestCase/接口/JoyHubC/JoyhubC_LikeInfo.py
Normal file
151
dulizhan/test_case/TestCase/接口/JoyHubC/JoyhubC_LikeInfo.py
Normal file
@@ -0,0 +1,151 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
JoyHub C端点赞记录接口测试用例
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import time
|
||||||
|
import allure
|
||||||
|
import logging
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from dulizhan.library.BusinessKw.JoyHubC.LikeInfoManage import JoyHubCLikeInfoManage
|
||||||
|
from dulizhan.library.BusinessKw.JoyHubC.NewsManage import JoyHubCNewsManage
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.skip(reason="点赞记录接口依赖C端登录态,当前鉴权方式未打通,暂时跳过")
|
||||||
|
@allure.feature("C端 - 点赞记录模块")
|
||||||
|
class TestJoyHubCLikeInfo:
|
||||||
|
like_id = None
|
||||||
|
data_id = None
|
||||||
|
device_id = None
|
||||||
|
like_type = 1
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setup_class(cls):
|
||||||
|
"""在整个测试类开始时初始化C端点赞记录业务关键字"""
|
||||||
|
logging.info("=============================================")
|
||||||
|
logging.info("=========== 开始JoyHub C端点赞记录接口测试 =========")
|
||||||
|
logging.info("=============================================")
|
||||||
|
cls.test_case = JoyHubCLikeInfoManage()
|
||||||
|
cls.news_case = JoyHubCNewsManage()
|
||||||
|
cls.device_id = f"auto_device_{int(time.time())}"
|
||||||
|
news_resp = cls.news_case.kw_joyhub_c_news_page_get(pageNo=1, pageSize=10)
|
||||||
|
if news_resp and news_resp.get("code") == 0 and news_resp.get("data", {}).get("list"):
|
||||||
|
cls.data_id = news_resp["data"]["list"][0].get("id")
|
||||||
|
|
||||||
|
@allure.story("验证C端创建点赞记录")
|
||||||
|
@allure.title("测试C端创建点赞记录接口")
|
||||||
|
def test_joyhub_c_like_info_create_post(self):
|
||||||
|
"""测试C端创建点赞记录接口"""
|
||||||
|
if not TestJoyHubCLikeInfo.data_id:
|
||||||
|
pytest.skip("没有可用于点赞的news数据")
|
||||||
|
|
||||||
|
with allure.step("1. 准备请求参数"):
|
||||||
|
params = {
|
||||||
|
"id": int(time.time()),
|
||||||
|
"type": TestJoyHubCLikeInfo.like_type,
|
||||||
|
"dataId": TestJoyHubCLikeInfo.data_id,
|
||||||
|
"deviceId": TestJoyHubCLikeInfo.device_id
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用创建点赞记录接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_c_like_info_create_post(**params)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
if resp["code"] == 300034:
|
||||||
|
pytest.skip("创建点赞记录接口依赖C端登录态,当前登录鉴权方式未打通")
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert resp["data"] is not None, "data字段为空"
|
||||||
|
TestJoyHubCLikeInfo.like_id = resp["data"]
|
||||||
|
logging.info("C端创建点赞记录接口验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证C端获得点赞记录分页")
|
||||||
|
@allure.title("测试C端获得点赞记录分页接口")
|
||||||
|
def test_joyhub_c_like_info_page_get(self):
|
||||||
|
"""测试C端获得点赞记录分页接口"""
|
||||||
|
with allure.step("1. 准备请求参数"):
|
||||||
|
params = {
|
||||||
|
"pageNo": 1,
|
||||||
|
"pageSize": 10
|
||||||
|
}
|
||||||
|
if TestJoyHubCLikeInfo.data_id:
|
||||||
|
params["type"] = TestJoyHubCLikeInfo.like_type
|
||||||
|
params["dataId"] = TestJoyHubCLikeInfo.data_id
|
||||||
|
params["deviceId"] = TestJoyHubCLikeInfo.device_id
|
||||||
|
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用获得点赞记录分页接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_c_like_info_page_get(**params)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert "list" in resp["data"], "响应中缺少list字段"
|
||||||
|
assert isinstance(resp["data"]["list"], list), "list字段不是列表类型"
|
||||||
|
if not TestJoyHubCLikeInfo.like_id and resp["data"]["list"]:
|
||||||
|
TestJoyHubCLikeInfo.like_id = resp["data"]["list"][0].get("id")
|
||||||
|
logging.info("C端获得点赞记录分页接口验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证C端获得点赞记录")
|
||||||
|
@allure.title("测试C端获得点赞记录接口")
|
||||||
|
def test_joyhub_c_like_info_get_get(self):
|
||||||
|
"""测试C端获得点赞记录接口"""
|
||||||
|
if not TestJoyHubCLikeInfo.like_id:
|
||||||
|
pytest.skip("没有可用于查询详情的点赞记录")
|
||||||
|
|
||||||
|
with allure.step("1. 准备请求参数"):
|
||||||
|
params = {
|
||||||
|
"id": TestJoyHubCLikeInfo.like_id
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用获得点赞记录接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_c_like_info_get_get(**params)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert resp["data"] is not None, "data字段为空"
|
||||||
|
assert resp["data"].get("id") == TestJoyHubCLikeInfo.like_id, "返回的点赞记录ID与请求ID不一致"
|
||||||
|
logging.info("C端获得点赞记录接口验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证C端取消点赞")
|
||||||
|
@allure.title("测试C端取消点赞接口")
|
||||||
|
def test_joyhub_c_like_info_delete_post(self):
|
||||||
|
"""测试C端取消点赞接口"""
|
||||||
|
if not TestJoyHubCLikeInfo.like_id:
|
||||||
|
pytest.skip("没有可用于取消点赞的点赞记录")
|
||||||
|
|
||||||
|
with allure.step("1. 准备请求参数"):
|
||||||
|
params = {
|
||||||
|
"id": TestJoyHubCLikeInfo.like_id,
|
||||||
|
"type": TestJoyHubCLikeInfo.like_type,
|
||||||
|
"dataId": TestJoyHubCLikeInfo.data_id,
|
||||||
|
"deviceId": TestJoyHubCLikeInfo.device_id
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用取消点赞接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_c_like_info_delete_post(**params)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert isinstance(resp["data"], bool), "data字段不是布尔类型"
|
||||||
|
logging.info("C端取消点赞接口验证通过")
|
||||||
110
dulizhan/test_case/TestCase/接口/JoyHubC/JoyhubC_News.py
Normal file
110
dulizhan/test_case/TestCase/接口/JoyHubC/JoyhubC_News.py
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
JoyHub C端news管理接口测试用例
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import allure
|
||||||
|
import logging
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from dulizhan.library.BusinessKw.JoyHubC.NewsManage import JoyHubCNewsManage
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("C端 - news管理模块")
|
||||||
|
class TestJoyHubCNews:
|
||||||
|
news_id = None
|
||||||
|
news_cate_id = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setup_class(cls):
|
||||||
|
"""在整个测试类开始时初始化C端news管理业务关键字"""
|
||||||
|
logging.info("=============================================")
|
||||||
|
logging.info("=========== 开始JoyHub C端news管理接口测试 =========")
|
||||||
|
logging.info("=============================================")
|
||||||
|
cls.test_case = JoyHubCNewsManage()
|
||||||
|
|
||||||
|
@allure.story("验证C端获得news管理分页")
|
||||||
|
@allure.title("测试C端获得news管理分页接口")
|
||||||
|
def test_joyhub_c_news_page_get(self):
|
||||||
|
"""测试C端获得news管理分页接口"""
|
||||||
|
with allure.step("1. 准备请求参数"):
|
||||||
|
params = {
|
||||||
|
"pageNo": 1,
|
||||||
|
"pageSize": 10
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用获得news管理分页接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_c_news_page_get(**params)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert "list" in resp["data"], "响应中缺少list字段"
|
||||||
|
assert isinstance(resp["data"]["list"], list), "list字段不是列表类型"
|
||||||
|
if "total" in resp["data"]:
|
||||||
|
assert isinstance(resp["data"]["total"], int), "total字段不是整数类型"
|
||||||
|
if resp["data"]["list"]:
|
||||||
|
first_news = resp["data"]["list"][0]
|
||||||
|
TestJoyHubCNews.news_id = first_news.get("id")
|
||||||
|
TestJoyHubCNews.news_cate_id = first_news.get("cateId")
|
||||||
|
logging.info("C端获得news管理分页接口验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证C端获得news详情")
|
||||||
|
@allure.title("测试C端获得news详情接口")
|
||||||
|
def test_joyhub_c_news_get_detail_get(self):
|
||||||
|
"""测试C端获得news详情接口"""
|
||||||
|
if not TestJoyHubCNews.news_id:
|
||||||
|
pytest.skip("没有可用于查询详情的news数据")
|
||||||
|
|
||||||
|
with allure.step("1. 准备请求参数"):
|
||||||
|
params = {
|
||||||
|
"id": TestJoyHubCNews.news_id
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用获得news详情接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_c_news_get_detail_get(**params)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert resp["data"] is not None, "data字段为空"
|
||||||
|
assert resp["data"].get("id") == TestJoyHubCNews.news_id, "返回的news ID与请求ID不一致"
|
||||||
|
logging.info("C端获得news详情接口验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证C端获得news下一条")
|
||||||
|
@allure.title("测试C端获得news下一条接口")
|
||||||
|
def test_joyhub_c_news_get_next_get(self):
|
||||||
|
"""测试C端获得news下一条接口"""
|
||||||
|
if not TestJoyHubCNews.news_id:
|
||||||
|
pytest.skip("没有可用于查询下一条的news数据")
|
||||||
|
|
||||||
|
with allure.step("1. 准备请求参数"):
|
||||||
|
params = {
|
||||||
|
"id": TestJoyHubCNews.news_id
|
||||||
|
}
|
||||||
|
if TestJoyHubCNews.news_cate_id:
|
||||||
|
params["cateId"] = TestJoyHubCNews.news_cate_id
|
||||||
|
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用获得news下一条接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_c_news_get_next_get(**params)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
if resp["data"] is not None:
|
||||||
|
assert isinstance(resp["data"], dict), "data字段不是字典类型"
|
||||||
|
logging.info("C端获得news下一条接口验证通过")
|
||||||
39
dulizhan/test_case/TestCase/接口/JoyHubC/JoyhubC_NewsCate.py
Normal file
39
dulizhan/test_case/TestCase/接口/JoyHubC/JoyhubC_NewsCate.py
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
JoyHub C端news分类接口测试用例
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import allure
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from dulizhan.library.BusinessKw.JoyHubC.NewsCateManage import JoyHubCNewsCateManage
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("C端 - news分类模块")
|
||||||
|
class TestJoyHubCNewsCate:
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setup_class(cls):
|
||||||
|
"""在整个测试类开始时初始化C端news分类业务关键字"""
|
||||||
|
logging.info("=============================================")
|
||||||
|
logging.info("=========== 开始JoyHub C端news分类接口测试 =========")
|
||||||
|
logging.info("=============================================")
|
||||||
|
cls.test_case = JoyHubCNewsCateManage()
|
||||||
|
|
||||||
|
@allure.story("验证C端获得news分类列表")
|
||||||
|
@allure.title("测试C端获得news分类列表接口")
|
||||||
|
def test_joyhub_c_news_cate_list_get(self):
|
||||||
|
"""测试C端获得news分类列表接口"""
|
||||||
|
with allure.step("1. 调用获得news分类列表接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_c_news_cate_list_get()
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("2. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert isinstance(resp["data"], list), "data字段不是列表类型"
|
||||||
|
logging.info("C端获得news分类列表接口验证通过")
|
||||||
86
dulizhan/test_case/TestCase/接口/JoyHubC/JoyhubC_Product.py
Normal file
86
dulizhan/test_case/TestCase/接口/JoyHubC/JoyhubC_Product.py
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
JoyHub C端产品接口测试用例
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import allure
|
||||||
|
import logging
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from dulizhan.library.BusinessKw.JoyHubC.ProductManage import JoyHubCProductManage
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("C端 - 产品模块")
|
||||||
|
class TestJoyHubCProduct:
|
||||||
|
product_route = "vibrators-cherly"
|
||||||
|
country_code = "US"
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setup_class(cls):
|
||||||
|
"""在整个测试类开始时初始化C端产品业务关键字"""
|
||||||
|
logging.info("=============================================")
|
||||||
|
logging.info("=========== 开始JoyHub C端产品接口测试 =========")
|
||||||
|
logging.info("=============================================")
|
||||||
|
cls.test_case = JoyHubCProductManage()
|
||||||
|
|
||||||
|
@allure.story("验证C端获得产品分页")
|
||||||
|
@allure.title("测试C端获得产品分页接口")
|
||||||
|
def test_joyhub_c_product_page_get(self):
|
||||||
|
"""测试C端获得产品分页接口"""
|
||||||
|
with allure.step("1. 准备请求参数"):
|
||||||
|
params = {
|
||||||
|
"productCateId": 1,
|
||||||
|
"countryCode": TestJoyHubCProduct.country_code,
|
||||||
|
"pageNo": 1,
|
||||||
|
"pageSize": 10
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用获得产品分页接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_c_product_page_get(**params)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert "list" in resp["data"], "响应中缺少list字段"
|
||||||
|
assert isinstance(resp["data"]["list"], list), "list字段不是列表类型"
|
||||||
|
if "total" in resp["data"]:
|
||||||
|
assert isinstance(resp["data"]["total"], int), "total字段不是整数类型"
|
||||||
|
if resp["data"]["list"]:
|
||||||
|
first_product = resp["data"]["list"][0]
|
||||||
|
TestJoyHubCProduct.product_route = first_product.get("route")
|
||||||
|
logging.info("C端获得产品分页接口验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证C端产品详情")
|
||||||
|
@allure.title("测试C端产品详情接口")
|
||||||
|
def test_joyhub_c_product_get_get(self):
|
||||||
|
"""测试C端产品详情接口"""
|
||||||
|
if not TestJoyHubCProduct.product_route:
|
||||||
|
pytest.skip("没有可用于查询详情的产品数据")
|
||||||
|
|
||||||
|
with allure.step("1. 准备请求参数"):
|
||||||
|
params = {
|
||||||
|
"route": TestJoyHubCProduct.product_route,
|
||||||
|
"countryCode": TestJoyHubCProduct.country_code
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用产品详情接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_c_product_get_get(**params)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert resp["data"] is not None, "data字段为空"
|
||||||
|
assert isinstance(resp["data"], dict), "data字段不是字典类型"
|
||||||
|
if resp["data"].get("route"):
|
||||||
|
assert resp["data"].get("route") == TestJoyHubCProduct.product_route, "返回的产品route与请求route不一致"
|
||||||
|
logging.info("C端产品详情接口验证通过")
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
JoyHub C端支付页产品推荐接口测试用例
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import allure
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from dulizhan.library.BusinessKw.JoyHubC.ProductPaymentRecommendManage import JoyHubCProductPaymentRecommendManage
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("C端 - 支付页产品推荐模块")
|
||||||
|
class TestJoyHubCProductPaymentRecommend:
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setup_class(cls):
|
||||||
|
"""在整个测试类开始时初始化C端支付页产品推荐业务关键字"""
|
||||||
|
logging.info("=============================================")
|
||||||
|
logging.info("=========== 开始JoyHub C端支付页产品推荐接口测试 =========")
|
||||||
|
logging.info("=============================================")
|
||||||
|
cls.test_case = JoyHubCProductPaymentRecommendManage()
|
||||||
|
|
||||||
|
@allure.story("验证C端获得支付页产品推荐分页")
|
||||||
|
@allure.title("测试C端获得支付页产品推荐分页接口")
|
||||||
|
def test_joyhub_c_product_payment_recommend_page_get(self):
|
||||||
|
"""测试C端获得支付页产品推荐分页接口"""
|
||||||
|
with allure.step("1. 准备请求参数"):
|
||||||
|
params = {
|
||||||
|
"pageNo": 1,
|
||||||
|
"pageSize": 10
|
||||||
|
}
|
||||||
|
allure.attach(json.dumps(params, ensure_ascii=False), name="请求参数", attachment_type=allure.attachment_type.TEXT)
|
||||||
|
|
||||||
|
with allure.step("2. 调用获得支付页产品推荐分页接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_c_product_payment_recommend_page_get(**params)
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert "list" in resp["data"], "响应中缺少list字段"
|
||||||
|
assert isinstance(resp["data"]["list"], list), "list字段不是列表类型"
|
||||||
|
if "total" in resp["data"]:
|
||||||
|
assert isinstance(resp["data"]["total"], int), "total字段不是整数类型"
|
||||||
|
logging.info("C端获得支付页产品推荐分页接口验证通过")
|
||||||
58
dulizhan/test_case/TestCase/接口/JoyHubC/JoyhubC_UserPoint.py
Normal file
58
dulizhan/test_case/TestCase/接口/JoyHubC/JoyhubC_UserPoint.py
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
# -*- coding:utf-8 -*-
|
||||||
|
"""
|
||||||
|
JoyHub C端查询当前用户积分接口测试用例
|
||||||
|
"""
|
||||||
|
import json
|
||||||
|
import allure
|
||||||
|
import logging
|
||||||
|
import pytest
|
||||||
|
|
||||||
|
from dulizhan.library.BusinessKw.JoyHubC.UserManage import JoyHubCUserManage
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
|
||||||
|
|
||||||
|
|
||||||
|
@allure.feature("C端 - 用户模块")
|
||||||
|
class TestJoyHubCUserPoint:
|
||||||
|
login_resp = None
|
||||||
|
login_success = False
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setup_class(cls):
|
||||||
|
"""在整个测试类开始时先调用C端登录接口"""
|
||||||
|
logging.info("=============================================")
|
||||||
|
logging.info("=========== 开始JoyHub C端登录 =========")
|
||||||
|
logging.info("=============================================")
|
||||||
|
|
||||||
|
cls.test_case = JoyHubCUserManage()
|
||||||
|
cls.login_resp = cls.test_case.kw_joyhub_c_login()
|
||||||
|
cls.login_success = cls.test_case.joyhub_c_token is not None
|
||||||
|
assert cls.login_success is True, "JoyHub C端登录失败,未获取到Token"
|
||||||
|
logging.info("JoyHub C端登录成功,Token已设置")
|
||||||
|
|
||||||
|
@allure.story("验证C端登录")
|
||||||
|
@allure.title("测试C端登录")
|
||||||
|
def test_joyhub_c_login(self):
|
||||||
|
"""测试C端登录"""
|
||||||
|
assert TestJoyHubCUserPoint.login_success is True, "C端登录失败"
|
||||||
|
logging.info("C端登录验证通过")
|
||||||
|
|
||||||
|
@allure.story("验证查询当前用户积分")
|
||||||
|
@allure.title("测试查询当前用户积分接口")
|
||||||
|
@pytest.mark.skip(reason="积分接口鉴权方式与当前C端登录token不一致,待确认真实鉴权头后恢复")
|
||||||
|
def test_joyhub_c_client_get_point_get(self):
|
||||||
|
"""测试查询当前用户积分接口"""
|
||||||
|
with allure.step("1. 确认C端已登录"):
|
||||||
|
assert TestJoyHubCUserPoint.login_success is True, "C端未登录,无法查询当前用户积分"
|
||||||
|
|
||||||
|
with allure.step("2. 调用查询当前用户积分接口"):
|
||||||
|
resp = self.test_case.kw_joyhub_c_client_get_point_get()
|
||||||
|
allure.attach(json.dumps(resp, ensure_ascii=False, indent=2), name="响应数据", attachment_type=allure.attachment_type.JSON)
|
||||||
|
|
||||||
|
with allure.step("3. 验证响应"):
|
||||||
|
assert resp is not None, "响应为空"
|
||||||
|
assert "code" in resp, "响应中缺少code字段"
|
||||||
|
assert resp["code"] == 0, f"请求失败,code={resp.get('code')}, msg={resp.get('msg')}"
|
||||||
|
assert "data" in resp, "响应中缺少data字段"
|
||||||
|
assert resp["data"] is not None, "data字段为空"
|
||||||
|
logging.info("查询当前用户积分接口验证通过")
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user