← 中文资源

简体中文版本

视觉回归测试

视觉回归测试对渲染后的页面或组件截图,与已批准基线做像素级感知 diff,抓到 DOM 断言与功能测试都看不见的样式破坏。

阅读英文原文

概念定义

DOM 断言验证结构与行为;渲染结果——用户真正看到的——是另一个面。视觉回归逐像素 diff 那个面,把不可见的样式回归变成可评审的工件。

工作机制

浏览器按受控视口、主题与动画状态渲染目标,捕获确定性截图;diff 算法与基线比较并容忍渲染噪声。组件隔离消除页面级 flaky;整页捕获抓集成级联破坏。失败产出供人判读的 diff 图。

使用场景

令牌变更会波及全身的设计系统、跨断点的响应式布局、主题与暗色模式、以及“外观即产品”的营销页。截图要覆盖真实支持的断点矩阵而不是单一桌面视口。

常见误区

它是功能测试的补充不是替代:页面可以看起来一模一样而什么都不干,也可以功能完好而面目全非。严格像素比较在字体光栅与 GPU 差异上必 flaky——感知阈值加稳定环境才是手艺;基线失败即自动更新等于把套件变成无评审的变更记录仪。单视口整页快照会错过移动断点上的回归,显式捕获断点矩阵。

代码示例

use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Arc;
use std::time::Duration;

#[derive(Clone)]
struct FakeClock {
    millis: Arc<AtomicU64>,
}

impl FakeClock {
    fn new() -> Self {
        Self {
            millis: Arc::new(AtomicU64::new(0)),
        }
    }

    fn now(&self) -> Duration {
        Duration::from_millis(self.millis.load(Ordering::SeqCst))
    }

    fn advance(&self, delta: Duration) {
        self.millis
            .fetch_add(delta.as_millis() as u64, Ordering::SeqCst);
    }
}

struct Token {
    expires_at: Duration,
}

impl Token {
    fn issue(clock: &FakeClock, ttl: Duration) -> Self {
        Self {
            expires_at: clock.now() + ttl,
        }
    }

    fn expired(&self, clock: &FakeClock) -> bool {
        clock.now() >= self.expires_at
    }
}

fn main() {
    let clock = FakeClock::new();
    let token = Token::issue(&clock, Duration::from_secs(60));
    clock.advance(Duration::from_secs(59));
    println!("expired at 59s: {}", token.expired(&clock));
    clock.advance(Duration::from_secs(1));
    println!("expired at 60s: {}", token.expired(&clock));
}