Playwright Python — справочникНа главный сайт

Обзор

WebView2 — это элемент управления Microsoft Edge (Chromium), встраиваемый в десктопные приложения (WPF, WinForms, WinUI, C++). Playwright может подключаться к WebView2 через протокол CDP (Chrome DevTools Protocol) и управлять им как обычной страницей браузера.

Как это работает: Приложение с WebView2 запускается с флагом --remote-debugging-port=PORT. Playwright подключается к этому порту через connect_over_cdp() и получает доступ ко всем страницам WebView2.

Подключение через connect_over_cdp()

from playwright.sync_api import sync_playwright

with sync_playwright() as p:
    # Подключаемся к WebView2 через CDP
    browser = p.chromium.connect_over_cdp("http://localhost:9222")
    context = browser.contexts[0]
    page = context.pages[0]
    page.goto("https://example.com")
    print(page.title())

Включение CDP в приложении

При запуске десктопного приложения с WebView2 передайте аргументы командной строки в среду WebView2:

# C# (WPF) — пример включения удалённой отладки
webView2.CoreWebView2.OpenDevToolsWindow();

# Или через переменные среды перед запуском приложения
# set WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS=--remote-debugging-port=9222

Переменная окружения:

# Windows (CMD)
set WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS="--remote-debugging-port=9222"

# Python
import os
os.environ["WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS"] = \
    "--remote-debugging-port=9222"

Изоляция тестов: WEBVIEW2_USER_DATA_FOLDER

Каждый тест должен использовать отдельную папку для пользовательских данных WebView2. Это обеспечивает изоляцию сессий:

os.environ["WEBVIEW2_USER_DATA_FOLDER"] = f"./webview2-data-{test_id}"

Поиск свободного порта

import socket

def find_free_port():
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        s.bind(("", 0))
        return s.getsockname()[1]

port = find_free_port()
os.environ["WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS"] = \
    f"--remote-debugging-port={port}"

Полный пример conftest.py

# conftest.py
import pytest
import subprocess
import socket
import os
import time
from playwright.sync_api import sync_playwright

def find_free_port():
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        s.bind(("", 0))
        return s.getsockname()[1]

@pytest.fixture(scope="session")
def webview2_app():
    # Находим свободный порт
    port = find_free_port()
    os.environ["WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS"] = \
        f"--remote-debugging-port={port}"
    os.environ["WEBVIEW2_USER_DATA_FOLDER"] = \
        f"./webview2-test-session-{port}"

    # Запускаем десктопное приложение
    proc = subprocess.Popen([
        "path/to/your/app.exe",
        "--url", "https://example.com"
    ])
    time.sleep(2)  # ждём запуск
    yield (port, proc)
    proc.terminate()
    proc.wait()

@pytest.fixture
def page(webview2_app):
    port, _ = webview2_app
    with sync_playwright() as p:
        browser = p.chromium.connect_over_cdp(
            f"http://localhost:{port}"
        )
        context = browser.contexts[0]
        page = context.pages[0]
        yield page
        browser.close()

Использование в тестах

# test_app.py
def test_title(page):
    page.goto("https://example.com")
    assert page.title() == "Example Domain"

def test_screenshot(page):
    page.goto("https://example.com")
    page.screenshot(path="example.png")

def test_network_mock(page):
    page.route("**/api/data", lambda route: route.fulfill(
        status=200,
        content_type="application/json",
        body='{"result": "ok"}'
    ))
    page.goto("https://example.com")
Совет: Полный API Playwright (route, screenshot, evaluate, wait_for_selector и т.д.) доступен для WebView2. Нет ограничений по сравнению с обычной страницей браузера. Единственное отличие — способ подключения.

Отладка WebView2

Во время разработки можно открыть инструменты разработчика WebView2 программно:

# В коде приложения (C#)
webView2.CoreWebView2.OpenDevToolsWindow();

# Или нажать F12, если окно дебага включено

Через Playwright отладка работает стандартно:

page.pause()  # открывает инспектор Playwright

Полный пример теста WebView2

import pytest
import subprocess
import socket
import os
import time
from playwright.sync_api import sync_playwright

PORT = 9222
APP_PATH = "C:\\Program Files\\MyApp\\app.exe"

@pytest.fixture(scope="module")
def webview2_page():
    os.environ["WEBVIEW2_ADDITIONAL_BROWSER_ARGUMENTS"] = \
        f"--remote-debugging-port={PORT}"
    os.environ["WEBVIEW2_USER_DATA_FOLDER"] = \
        f"./webview2-data-{PORT}"

    proc = subprocess.Popen([APP_PATH])
    time.sleep(3)

    with sync_playwright() as p:
        browser = p.chromium.connect_over_cdp(
            f"http://localhost:{PORT}"
        )
        context = browser.contexts[0]
        page = context.new_page()
        yield page
        browser.close()

    proc.terminate()
    proc.wait()

def test_login(webview2_page):
    page = webview2_page
    page.goto("https://app.example.com/login")
    page.fill("#user", "admin")
    page.fill("#pass", "secret")
    page.click("button[type='submit']")
    assert page.locator(".dashboard").is_visible()

def test_screenshot(webview2_page):
    page = webview2_page
    page.goto("https://app.example.com/profile")
    page.screenshot(path="profile.png", full_page=True)
Внимание: Убедитесь, что приложение с WebView2 запущено до вызова connect_over_cdp(). Если порт недоступен, Playwright выбросит исключение. Используйте time.sleep() или цикл ожидания с повторными попытками подключения.