Files
agent-radar 1a3a4ccde1
Creator App Tests / PR Spam Gate (push) Skipped
Frontend Tests / PR Spam Gate (push) Skipped
NPM Format (website & console) / PR Spam Gate (push) Skipped
Pre-commit Checks / PR Spam Gate (push) Skipped
QwenPaw Creator Plugin Release / check-version (push) Canceled after 0s
QwenPaw Creator Plugin Release / upload-oss (push) Canceled after 0s
Tests / PR Spam Gate (push) Skipped
CodeQL / CodeQL (python) (push) Canceled after 0s
CodeQL / CodeQL (typescript) (push) Canceled after 0s
Creator App Tests / Creator Backend Tests (push) Canceled after 0s
Creator App Tests / Creator UI Build & Tests (push) Canceled after 0s
E2E Smoke Tests / Playwright UI Smoke (push) Canceled after 0s
Frontend Tests / Detect console changes (push) Canceled after 0s
NPM Format (website & console) / website format check (push) Canceled after 0s
NPM Format (website & console) / console format check (push) Canceled after 0s
Pre-commit Checks / Pre-commit (push) Canceled after 0s
QwenPaw Data Plugin Release / check-version (push) Canceled after 0s
Tests / Detect code changes (push) Canceled after 0s
Frontend Tests / Vitest Unit Tests (push) Canceled after 0s
Frontend Tests / Frontend Summary (push) Canceled after 0s
QwenPaw Data Plugin Release / upload-oss (push) Canceled after 0s
Tests / Maintainer Approval (push) Canceled after 0s
Tests / Unit Tests - py3.11 - macos-latest (push) Canceled after 0s
Tests / Unit Tests - py3.11 - ubuntu-latest (push) Canceled after 0s
Tests / Unit Tests - py3.13 - ubuntu-latest (push) Canceled after 0s
Tests / Unit Tests - py3.11 - windows-latest (push) Canceled after 0s
Tests / Contract Tests - py3.11 - macos-latest (push) Canceled after 0s
Tests / Contract Tests - py3.11 - ubuntu-latest (push) Canceled after 0s
Tests / Contract Tests - py3.13 - ubuntu-latest (push) Canceled after 0s
Tests / Contract Tests - py3.11 - windows-latest (push) Canceled after 0s
Tests / Integrated Tests - py3.11 - macos-latest - p0 (push) Canceled after 0s
Tests / Integrated Tests - py3.11 - macos-latest - p1 (push) Canceled after 0s
Tests / Integrated Tests - py3.11 - macos-latest - p2 (push) Canceled after 0s
Tests / Integrated Tests - py3.11 - ubuntu-latest - fallback (push) Canceled after 0s
Tests / Integrated Tests - py3.11 - ubuntu-latest - p0 (push) Canceled after 0s
Tests / Integrated Tests - py3.11 - ubuntu-latest - p1 (push) Canceled after 0s
Tests / Integrated Tests - py3.11 - ubuntu-latest - p2 (push) Canceled after 0s
Tests / Integrated Tests - py3.13 - ubuntu-latest - p0 (push) Canceled after 0s
Tests / Integrated Tests - py3.13 - ubuntu-latest - p1 (push) Canceled after 0s
Tests / Integrated Tests - py3.13 - ubuntu-latest - p2 (push) Canceled after 0s
Tests / Integrated Tests - py3.11 - windows-latest - p0 (push) Canceled after 0s
Tests / Integrated Tests - py3.11 - windows-latest - p1 (push) Canceled after 0s
Tests / Integrated Tests - py3.11 - windows-latest - p2 (push) Canceled after 0s
Tests / Coverage Report (push) Canceled after 0s
Tests / Test Summary (push) Canceled after 0s
源码快照 @ 2026-09-01 (source-only, 剔除非源码素材)
2026-09-01 20:01:50 +08:00

108 lines
3.8 KiB
Python

# -*- coding: utf-8 -*-
"""
QwenPaw Models page object.
Wraps all interactions on the Models page and exposes business-level methods.
"""
from __future__ import annotations
import logging
from typing import Optional, List, Dict, Any
from playwright.sync_api import Page, Locator, expect, TimeoutError
from pages.base_page import BasePage
from config.settings import config
logger = logging.getLogger(__name__)
class ModelsPage(BasePage):
"""
Models page object.
Wraps all user interactions on the Models page:
- Open the models page
- Get the breadcrumb
- Click the download model button
- Get the model list
"""
PAGE_TITLE = "QwenPaw Console"
MODELS_URL = f"{config.base_url}/models"
PAGE_URL = MODELS_URL
# ========== Selector definitions ==========
# Page load indicator
PAGE_LOAD_INDICATOR = '.ant-breadcrumb, .qwenpaw-breadcrumb, h1, h2, [class*="breadcrumb"]'
# Breadcrumb
BREADCRUMB_SELECTOR = '.ant-breadcrumb, .qwenpaw-breadcrumb, nav[class*="breadcrumb"], [class*="Breadcrumb"]'
# Download model button
DOWNLOAD_MODEL_BTN = 'button:has-text("下载模型"), button:has-text("Download Model"), button:has-text("下载"), button:has-text("Download")'
# Model list
MODEL_LIST_SELECTOR = '.ant-list-item, .qwenpaw-list-item, [class*="modelItem"], [class*="model-item"], table tbody tr, .ant-table-row, .qwenpaw-table-row'
# ========== Navigation ==========
def open(self) -> "ModelsPage":
"""Open the Models page."""
logger.info("Opening Models page")
self.goto()
self.wait_for_page_loaded()
return self
def wait_for_page_loaded(self, timeout: Optional[int] = None) -> "ModelsPage":
"""Wait for the page to finish loading."""
timeout = timeout or self.timeout
expect(self.page.locator(self.PAGE_LOAD_INDICATOR).first).to_be_visible(timeout=timeout)
return self
# ========== Page element operations ==========
def get_breadcrumb(self) -> str:
"""Return the breadcrumb text."""
breadcrumb = self.page.locator(self.BREADCRUMB_SELECTOR).first
if breadcrumb.count() > 0:
return breadcrumb.inner_text()
return ""
def click_download_model(self) -> "ModelsPage":
"""Click the download model button."""
download_btn = self.page.locator(self.DOWNLOAD_MODEL_BTN).first
if download_btn.count() > 0:
download_btn.click()
logger.info("Clicked download model button")
else:
logger.warning("Download model button not found")
return self
def get_model_list(self) -> List[Locator]:
"""Return the model list."""
models = self.page.locator(self.MODEL_LIST_SELECTOR).all()
logger.info(f"Found {len(models)} models")
return models
# ========== Assertion methods ==========
def assert_breadcrumb_contains(self, expected_text: str, timeout: Optional[int] = None) -> "ModelsPage":
"""Assert the breadcrumb contains the given text."""
breadcrumb = self.page.locator(self.BREADCRUMB_SELECTOR).first
expect(breadcrumb).to_contain_text(expected_text, timeout=timeout or self.timeout)
return self
def assert_model_count(self, expected_count: int, timeout: Optional[int] = None) -> "ModelsPage":
"""Assert the model count."""
expect(self.page.locator(self.MODEL_LIST_SELECTOR)).to_have_count(
expected_count, timeout=timeout or self.timeout
)
return self
def assert_download_button_visible(self, timeout: Optional[int] = None) -> "ModelsPage":
"""Assert the download button is visible."""
download_btn = self.page.locator(self.DOWNLOAD_MODEL_BTN).first
expect(download_btn).to_be_visible(timeout=timeout or self.timeout)
return self