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
128 lines
3.7 KiB
Python
128 lines
3.7 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""Real Chromium contracts for the Playwright control-link provider."""
|
|
|
|
import pytest
|
|
|
|
from qwenpaw.browser.control_link.playwright.adapter import (
|
|
PlaywrightControlLink,
|
|
)
|
|
from qwenpaw.browser.errors import BrowserError
|
|
|
|
|
|
def _locator_spec(method: str, *args: str, **kwargs: str) -> list[dict]:
|
|
return [
|
|
{
|
|
"method": method,
|
|
"args": list(args),
|
|
"kwargs": [[key, value] for key, value in kwargs.items()],
|
|
},
|
|
]
|
|
|
|
|
|
@pytest.mark.p1
|
|
async def test_real_provider_isolates_sessions_and_profile(
|
|
fixture_url: str,
|
|
tmp_path,
|
|
) -> None:
|
|
"""Sessions and profile contexts use separate real Chromium state."""
|
|
link = PlaywrightControlLink()
|
|
first_owner = {"workspace_id": "ws", "session_id": "incognito"}
|
|
profile_owner = {"workspace_id": "ws", "session_id": "profile"}
|
|
try:
|
|
await link.request(
|
|
"open_session",
|
|
{**first_owner, "context": "incognito"},
|
|
)
|
|
await link.request(
|
|
"open_session",
|
|
{
|
|
**profile_owner,
|
|
"context": "profile",
|
|
"user_data_dir": str(tmp_path / "profile"),
|
|
},
|
|
)
|
|
first = await link.request(
|
|
"new_page",
|
|
{**first_owner, "url": fixture_url},
|
|
)
|
|
profile = await link.request(
|
|
"new_page",
|
|
profile_owner,
|
|
)
|
|
first_pages = await link.request("list_pages", first_owner)
|
|
profile_pages = await link.request("list_pages", profile_owner)
|
|
|
|
assert first["page_id"] != profile["page_id"]
|
|
assert {page["page_id"] for page in first_pages["pages"]} == {
|
|
first["page_id"],
|
|
}
|
|
assert {page["page_id"] for page in profile_pages["pages"]} == {
|
|
profile["page_id"],
|
|
}
|
|
finally:
|
|
await link.close_all()
|
|
|
|
|
|
@pytest.mark.p1
|
|
async def test_real_provider_observes_locates_and_acts(
|
|
fixture_url: str,
|
|
) -> None:
|
|
"""The provider reads and changes a real page through lazy locators."""
|
|
link = PlaywrightControlLink()
|
|
owner = {"workspace_id": "ws", "session_id": "session"}
|
|
try:
|
|
await link.request(
|
|
"open_session",
|
|
{**owner, "context": "incognito"},
|
|
)
|
|
opened = await link.request(
|
|
"new_page",
|
|
{**owner, "url": fixture_url},
|
|
)
|
|
count = await link.request(
|
|
"locator_count",
|
|
{
|
|
**owner,
|
|
"page_id": opened["page_id"],
|
|
"spec": _locator_spec("get_by_role", "button", name="登录"),
|
|
},
|
|
)
|
|
result = await link.request(
|
|
"locator_action",
|
|
{
|
|
**owner,
|
|
"page_id": opened["page_id"],
|
|
"spec": _locator_spec("get_by_role", "button", name="登录"),
|
|
"action": "click",
|
|
},
|
|
)
|
|
tree = await link.request(
|
|
"capture_tree",
|
|
{**owner, "page_id": opened["page_id"]},
|
|
)
|
|
|
|
assert count["count"] == 1
|
|
assert "click" in result["evidence"]
|
|
assert "Logged in" in str(tree["tree"])
|
|
finally:
|
|
await link.close_all()
|
|
|
|
|
|
@pytest.mark.p1
|
|
async def test_real_provider_rejects_unsupported_context_and_method() -> None:
|
|
link = PlaywrightControlLink()
|
|
try:
|
|
with pytest.raises(BrowserError):
|
|
await link.request(
|
|
"open_session",
|
|
{
|
|
"workspace_id": "ws",
|
|
"session_id": "attached",
|
|
"context": "attached",
|
|
},
|
|
)
|
|
with pytest.raises(BrowserError):
|
|
await link.request("no_such_method", {})
|
|
finally:
|
|
await link.close_all()
|