Files
MyGoNavi/internal/app/window_zoom_windows_test.go
Syngnat 2580e4d6f3 🐛 fix(window): 直接调 WebView2 zoom factor 零感知修复 Windows 字体异常
- 新增 ResetWebViewZoom RPC:从 ctx 反射拿 Wails 内部 *edge.Chromium,调 PutZoomFactor(1.0) 强制 WebView2 重算 D2D/DirectWrite 字体度量,完全不动窗口零动画
- 自动路径:maximised + restore + drift 时直接调 backend reset,告别 9848b8b2 之后字体偶发变大的取舍
- 手动路径:保留 Ctrl+Shift+0 快捷键作为兜底(优先 WebView2 reset,失败回退 toggle)
- 撤回上一版 CSS zoom nudge:实测在 WebView2 上不能修字体度量(度量缓存在 D2D 层不在 Chromium layout 层)
- 反射做了 3 层签名校验(frontend value / chromium 字段 / PutZoomFactor 方法签名),wails 升级破坏接口时返回 error 不让进程崩溃
- 新增 windows-only 反射逻辑测试 4 个、跨平台 RPC 行为测试 2 个、Ctrl+Shift+0 快捷键注册测试
2026-05-15 16:01:18 +08:00

88 lines
2.9 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//go:build windows
package app
import (
"context"
"strings"
"sync/atomic"
"testing"
)
// fakeChromium 模仿 *edge.Chromium 的接口:只需要 exported 的 PutZoomFactor(float64) 方法。
// 用于在不依赖真实 wails / WebView2 的情况下验证反射路径。
type fakeChromium struct {
called atomic.Int32
last atomic.Value // float64
}
func (f *fakeChromium) PutZoomFactor(factor float64) {
f.called.Add(1)
f.last.Store(factor)
}
// fakeFrontend 模仿 wails 的 internal/frontend/desktop/windows.Frontend
// unexported 字段 chromium 是 *fakeChromium 类型exported method PutZoomFactor
// 反射代码不依赖具体类型名,只检查 method signature。
type fakeFrontend struct {
chromium *fakeChromium
}
// 测试必须用 wails 一致的 string key "frontend" 作为 context.WithValue 的 key
// 否则反射拿不到。go vet 会警告 string key用本地 stringContextKey 帮助函数封装来抑制。
// 这层封装等价于直接传字符串字面量,行为完全一致。
func stringContextKey(key string) any {
type contextKeyAlias = string
return contextKeyAlias(key)
}
func TestResetWebViewZoomFactorCallsPutZoomFactor(t *testing.T) {
chromium := &fakeChromium{}
ctx := context.WithValue(context.Background(), stringContextKey("frontend"), &fakeFrontend{chromium: chromium})
if err := resetWebViewZoomFactor(ctx, 1.0); err != nil {
t.Fatalf("expected reset to succeed against fake frontend, got %v", err)
}
if got := chromium.called.Load(); got != 1 {
t.Fatalf("expected PutZoomFactor called exactly once, got %d", got)
}
if got, _ := chromium.last.Load().(float64); got != 1.0 {
t.Fatalf("expected factor 1.0, got %v", got)
}
}
func TestResetWebViewZoomFactorErrorsWhenChromiumFieldMissing(t *testing.T) {
type fakeFrontendWithoutChromium struct {
other string
}
ctx := context.WithValue(context.Background(), stringContextKey("frontend"), &fakeFrontendWithoutChromium{})
err := resetWebViewZoomFactor(ctx, 1.0)
if err == nil {
t.Fatal("expected error when chromium field is missing, got nil")
}
if !strings.Contains(err.Error(), "chromium") {
t.Fatalf("expected error to mention chromium, got %v", err)
}
}
func TestResetWebViewZoomFactorErrorsWhenChromiumNil(t *testing.T) {
ctx := context.WithValue(context.Background(), stringContextKey("frontend"), &fakeFrontend{chromium: nil})
err := resetWebViewZoomFactor(ctx, 1.0)
if err == nil {
t.Fatal("expected error when chromium is nil, got nil")
}
if !strings.Contains(err.Error(), "nil") {
t.Fatalf("expected error to mention nil, got %v", err)
}
}
func TestResetWebViewZoomFactorErrorsWhenFrontendMissing(t *testing.T) {
err := resetWebViewZoomFactor(context.Background(), 1.0)
if err == nil {
t.Fatal("expected error when frontend not in ctx, got nil")
}
if !strings.Contains(err.Error(), "frontend") {
t.Fatalf("expected error to mention frontend, got %v", err)
}
}