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
60 lines
1.4 KiB
Python
60 lines
1.4 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""Every locator call named in the manual must exist on LocatorView."""
|
|
import re
|
|
|
|
from qwenpaw.browser.sdk import facade
|
|
from qwenpaw.browser.sdk.contracts import LocatorView
|
|
|
|
_MANUAL = "".join(
|
|
value
|
|
for name in dir(facade)
|
|
if name.startswith("_BLOCK")
|
|
for value in [getattr(facade, name)]
|
|
if isinstance(value, str)
|
|
)
|
|
|
|
_CALL_RE = re.compile(r"\b([a-z_][a-z0-9_]*)\(")
|
|
|
|
_NON_LOCATOR_NAMES = {
|
|
"browser",
|
|
"connect",
|
|
"open",
|
|
"close",
|
|
"close_page",
|
|
"close_session",
|
|
"snapshot",
|
|
"current_surface",
|
|
"goto",
|
|
"screenshot",
|
|
"print",
|
|
"getting_started",
|
|
"get_by_role",
|
|
"get_by_label",
|
|
"get_by_text",
|
|
"get_by_placeholder",
|
|
"locator",
|
|
"frame_locator",
|
|
"handoff",
|
|
"activate_page",
|
|
"wait_for",
|
|
"session_status",
|
|
"len",
|
|
"splitlines",
|
|
"join",
|
|
}
|
|
|
|
|
|
def test_manual_locator_calls_exist_on_contract():
|
|
"""The manual cannot advertise locator methods absent from the SDK."""
|
|
advertised = set(_CALL_RE.findall(_MANUAL)) - _NON_LOCATOR_NAMES
|
|
missing = sorted(
|
|
name for name in advertised if not hasattr(LocatorView, name)
|
|
)
|
|
assert missing == []
|
|
|
|
|
|
def test_removed_surface_not_advertised():
|
|
"""Removed and property-only calls cannot return to the manual."""
|
|
for banned in ("evaluate(", "drag(", "first()", "last()"):
|
|
assert banned not in _MANUAL
|