"""Does pythonnet fire NavigationCompleted for a real page load? This validates the mechanism the player relies on to tell "page loaded" apart from "page failed" (e.g. unreachable host on a closed network). If the event does not fire, the player cannot detect a failed weblink and would show Chromium's error page for the full slot. Checks three things: 1. the delegate can be constructed and subscribed, 2. it fires for a GOOD page -> IsSuccess True, 3. it fires for a BAD page -> IsSuccess False. Run: windows\\venv\\Scripts\\python.exe windows\\test_webview2_navigation.py Exit code 0 = PASS. """ import ctypes import http.server import socketserver import sys import threading import time from pathlib import Path sys.path.insert(0, str(Path(__file__).resolve().parent)) PORT = 18766 PAGE = '

KIWY-NAV-OK

' class _Handler(http.server.BaseHTTPRequestHandler): def do_GET(self): body = PAGE.encode() self.send_response(200) self.send_header('Content-Type', 'text/html') self.send_header('Content-Length', str(len(body))) self.end_headers() self.wfile.write(body) def log_message(self, *args): pass def _start_server(): socketserver.TCPServer.allow_reuse_address = True httpd = socketserver.TCPServer(('127.0.0.1', PORT), _Handler) threading.Thread(target=httpd.serve_forever, daemon=True).start() return httpd user32 = ctypes.windll.user32 kernel32 = ctypes.windll.kernel32 WNDPROC = ctypes.WINFUNCTYPE( ctypes.c_int64, ctypes.c_void_p, ctypes.c_uint, ctypes.c_void_p, ctypes.c_void_p ) @WNDPROC def _wnd_proc(hwnd, msg, wparam, lparam): if msg == 0x0002: user32.PostQuitMessage(0) return 0 user32.DefWindowProcW.restype = ctypes.c_int64 user32.DefWindowProcW.argtypes = [ ctypes.c_void_p, ctypes.c_uint, ctypes.c_void_p, ctypes.c_void_p, ] return user32.DefWindowProcW(hwnd, msg, wparam, lparam) def _make_window(width=1024, height=768): hinstance = kernel32.GetModuleHandleW(None) name = 'KiwyNavTest' class WNDCLASSEX(ctypes.Structure): _fields_ = [ ('cbSize', ctypes.c_uint), ('style', ctypes.c_uint), ('lpfnWndProc', WNDPROC), ('cbClsExtra', ctypes.c_int), ('cbWndExtra', ctypes.c_int), ('hInstance', ctypes.c_void_p), ('hIcon', ctypes.c_void_p), ('hCursor', ctypes.c_void_p), ('hbrBackground', ctypes.c_void_p), ('lpszMenuName', ctypes.c_wchar_p), ('lpszClassName', ctypes.c_wchar_p), ('hIconSm', ctypes.c_void_p), ] wc = WNDCLASSEX() wc.cbSize = ctypes.sizeof(WNDCLASSEX) wc.style = 0x0002 | 0x0001 wc.lpfnWndProc = _wnd_proc wc.hInstance = hinstance wc.hbrBackground = ctypes.c_void_p(6) wc.lpszClassName = name user32.RegisterClassExW(ctypes.byref(wc)) hwnd = user32.CreateWindowExW( 0, name, 'Kiwy Nav Test', 0x00CF0000 | 0x10000000, 40, 40, width, height, 0, 0, hinstance, 0, ) if not hwnd: raise RuntimeError('CreateWindowExW failed') user32.UpdateWindow(hwnd) return hwnd def _pump(seconds): import ctypes.wintypes as wt deadline = time.monotonic() + seconds while time.monotonic() < deadline: msg = wt.MSG() while user32.PeekMessageW(ctypes.byref(msg), None, 0, 0, 1): user32.TranslateMessage(ctypes.byref(msg)) user32.DispatchMessageW(ctypes.byref(msg)) time.sleep(0.02) def _drive(browser, seconds): deadline = time.monotonic() + seconds while time.monotonic() < deadline: browser._tick(0) _pump(0.05) def _wait_nav(browser, timeout): deadline = time.monotonic() + timeout while time.monotonic() < deadline: browser._tick(0) _pump(0.05) if browser.navigation_succeeded() is not None: return browser.navigation_succeeded() return None def main(): print('=' * 68) print(' WebView2 NavigationCompleted test') print('=' * 68) from webview2_browser import WebView2Browser if not WebView2Browser.is_available(): print('FAIL: WebView2 unavailable:', WebView2Browser._import_error) return 1 httpd = _start_server() good = f'http://127.0.0.1:{PORT}/index.html' # A port nothing listens on: guarantees a real navigation failure. bad = 'http://127.0.0.1:1/missing' hwnd = _make_window() browser = WebView2Browser(hwnd_provider=lambda: hwnd) ok = True print(f'\n[1] good page: {good}') browser.show(good) _drive(browser, 1.0) result = _wait_nav(browser, 20) print(f' navigation_succeeded = {result}') print(f' status = {browser.navigation_status()!r}') if result is not True: print(' FAIL: good page did not report success') ok = False print(f'\n[2] bad page: {bad}') browser.show(bad) _drive(browser, 1.0) result = _wait_nav(browser, 25) print(f' navigation_succeeded = {result}') print(f' status = {browser.navigation_status()!r}') if result is not False: print(' FAIL: bad page did not report failure') ok = False browser.shutdown() httpd.shutdown() httpd.server_close() print('=' * 68) print(' RESULT:', 'PASS' if ok else 'FAIL') if ok: print(' The player can tell a loaded page from a failed one,') print(' so unreachable weblinks are skipped instead of shown blank.') print('=' * 68) return 0 if ok else 1 if __name__ == '__main__': sys.exit(main())