WebView2
Тестирование WebView2 — элемент управления Edge в десктопных приложениях
Обзор
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() или цикл ожидания с повторными попытками подключения.