AI 前端项目验收:Playwright 截图、响应式视口、控制台错误与交互回归

本文适用于 AI 生成或 AI 辅助修改后的前端项目,目标是把"浏览器可以打开"升级为一套可重复的验收流程。

示例来自一个 Vite、TypeScript 与 Three.js 实现的四冲程发动机页面。实际浏览器验收覆盖:

  • 1600 × 900 桌面视口;
  • 390 × 844 移动视口;
  • 连续 12 秒的动画状态;
  • 播放、重置、滑块、剖视和四个相机预设;
  • 浏览器控制台与生产构建。

需要先说明:原项目完成了真实浏览器检查和截图验证,但没有新增一套 Playwright Test 自动化工程。本文代码是把这次人工验收过程整理成可复用测试模板,不把它写成原项目已经执行过的自动化测试结果。

1. 安装与启动

在待测项目前安装 Playwright Test:

bash 复制代码
npm install -D @playwright/test
npx playwright install chromium

先启动本地开发服务:

bash 复制代码
npm run dev -- --host 127.0.0.1

以下示例假定页面地址为:

text 复制代码
http://127.0.0.1:5173/

也可以在 playwright.config.ts 中配置 webServer,让测试命令自动启动服务:

ts 复制代码
import { defineConfig } from '@playwright/test';

export default defineConfig({
  use: {
    baseURL: 'http://127.0.0.1:5173',
    trace: 'retain-on-failure',
  },
  webServer: {
    command: 'npm run dev -- --host 127.0.0.1',
    url: 'http://127.0.0.1:5173',
    reuseExistingServer: true,
  },
});

2. 响应式视口:桌面与手机分别验收

Three.js 页面除了 DOM 布局,还要检查相机构图。宽屏镜头直接用于窄屏时,模型可能被顶部状态栏与底部控制面板夹住。

示例项目最终为桌面与移动端分别维护相机预设,并在跨过 640px 断点时回到对应的全景视角。测试时也应固定两个独立视口:

ts 复制代码
import { test, expect } from '@playwright/test';

const viewports = [
  { name: 'desktop', width: 1600, height: 900 },
  { name: 'mobile', width: 390, height: 844 },
];

for (const viewport of viewports) {
  test(`${viewport.name} viewport`, async ({ page }) => {
    await page.setViewportSize({
      width: viewport.width,
      height: viewport.height,
    });

    await page.goto('/');
    await expect(page.locator('canvas')).toBeVisible();
    await expect(page.getByRole('button', { name: /暂停/ })).toBeVisible();
  });
}

建议至少检查以下项目:

检查项 桌面端 移动端
关键主体 是否完整进入主视区 是否被顶部、底部 UI 遮挡
操作控件 是否全部可见、可点击 是否裁切或产生横向溢出
文本标签 是否与对象对应 是否被屏幕边缘裁切
Canvas 是否可见且非空白 调整尺寸后是否重新渲染

3. 动态页面:冻结业务动画后再做截图基线

Playwright Test 支持 expect(page).toHaveScreenshot()。第一次运行生成基线图,后续运行与基线比较。

但 WebGL 页面有一个额外问题:Canvas 通常由 requestAnimationFrame 持续更新。animations: 'disabled' 可以处理 CSS 动画,不会自动暂停 Three.js 渲染循环中的业务状态。

如果页面提供暂停按钮,应先暂停到稳定状态:

ts 复制代码
test('stable visual snapshot', async ({ page }) => {
  await page.setViewportSize({ width: 390, height: 844 });
  await page.goto('/');

  await page.getByRole('button', { name: /暂停/ }).click();
  await expect(page.getByRole('button', { name: /播放/ })).toBeVisible();

  await expect(page).toHaveScreenshot('engine-mobile.png', {
    animations: 'disabled',
    maxDiffPixelRatio: 0.01,
  });
});

如果项目没有暂停入口,可以在测试环境暴露确定性的时间控制接口,或让渲染逻辑接受固定时间值。不要依赖随机等待后截图,否则每次基线都可能停在不同帧。

Playwright 官方文档还提醒:截图会受到操作系统、浏览器版本、字体、硬件、供电状态和 headless 模式影响。基线与复测应保持同一运行环境,CI 中最好固定浏览器镜像。

4. 动画状态:不能只检查第一帧

发动机页面的四冲程由 720° 状态循环驱动。实际验收连续运行了 12 秒,并检查吸气、喷油、点火、做功和排气是否连贯。

这类页面应把业务状态验收与视觉截图分开:

  • 视觉截图回答"这一帧是否正确";
  • 状态断言回答"流程是否走到目标节点";
  • 完整运行回答"多个节点之间是否连续"。

以页面中的循环计数与阶段文字为例,可以等待状态变化:

ts 复制代码
test('cycle advances and can reset', async ({ page }) => {
  await page.goto('/');

  await expect(page.getByText('吸气', { exact: true })).toBeVisible();
  await expect(page.locator('#ro-cycle')).not.toHaveText('0', {
    timeout: 15_000,
  });

  await page.getByRole('button', { name: /重置/ }).click();
  await expect(page.locator('#ro-cycle')).toHaveText('0');
  await expect(page.locator('#ro-angle')).toHaveText('0°');
});

示例中的等待时间与当前默认转速和慢放倍率有关。更稳妥的工程做法是给测试提供可控时钟,而不是把业务速度硬编码进断言。

5. 交互回归:检查切换后的恢复状态

按钮"能点"还不够。相机特写、剖视和重置都会修改多处状态,测试应覆盖从一种状态切到另一种状态后的恢复结果。

ts 复制代码
test('camera presets and controls', async ({ page }) => {
  await page.goto('/');
  await page.getByRole('button', { name: /暂停/ }).click();

  for (const name of ['全景', '侧面', '缸内', '气门']) {
    await page.getByRole('button', { name, exact: true }).click();
    await page.waitForTimeout(450);
    await expect(page.locator('canvas')).toBeVisible();
  }

  await page.getByLabel(/剖视/).check();
  await expect(page.getByLabel(/剖视/)).toBeChecked();

  await page.locator('#in-rpm').fill('300');
  await expect(page.locator('#v-rpm')).toHaveText('300');

  await page.getByRole('button', { name: /重置/ }).click();
  await expect(page.locator('#ro-cycle')).toHaveText('0');
});

示例页面的相机缓动约为 400ms,因此代码等待 450ms。实际项目应优先等待可观察状态,例如按钮状态、目标元素或自定义完成事件;只有缺少可观察信号时才使用固定等待。

6. 控制台、页面异常与生产构建

运行时错误要在 goto() 之前监听:

ts 复制代码
test('no runtime errors', async ({ page }) => {
  const errors: string[] = [];

  page.on('console', (message) => {
    if (message.type() === 'error') errors.push(message.text());
  });

  page.on('pageerror', (error) => {
    errors.push(error.message);
  });

  await page.goto('/');
  await page.waitForTimeout(12_000);

  expect(errors).toEqual([]);
});

浏览器验收后还要运行生产构建:

bash 复制代码
npm run build

示例项目的 Vite/TypeScript 构建通过,桌面与移动端浏览器检查也没有 JavaScript 错误。构建仍提示主 JavaScript 包超过 500 kB。这属于需要记录和评估的体积警告,不等同于页面运行失败。

7. 推荐的最小验收清单

提交 AI 生成的前端代码前,至少完成以下检查:

  1. 固定桌面和移动视口并分别截图;
  2. 确认关键 DOM、Canvas 与操作控件可见;
  3. 让动画或异步流程覆盖完整业务状态;
  4. 冻结动态内容后生成视觉基线;
  5. 操作全部关键控件并检查恢复状态;
  6. 监听 console errorpageerror
  7. 运行生产构建并记录警告;
  8. 在固定环境中复测视觉差异。

"能打开"适合作为冒烟检查。只有视口、状态、交互和错误都得到明确结论,才适合作为交付验收。

标签:Playwright、AI 编程、前端测试、视觉回归、Three.js、响应式测试

相关推荐
Bruce_Liuxiaowei1 小时前
从基础理论开始学习人工智能(二):应用和方法——从拼图游戏到神经网络
人工智能·神经网络·学习
Java搬码工1 小时前
VUE3使用教程
前端·javascript·vue.js
Fnetlink11 小时前
解析SDWAN供应商光联世纪口碑佳的原因
网络·人工智能·安全
孫治AllenSun1 小时前
【LangChain4J-04】Tool 工具的使用
java·人工智能
小白勇闯网安圈1 小时前
Vue 3 核心进阶:组合式 API、响应式系统与 <script setup>
前端·javascript·vue.js
张风捷特烈1 小时前
当 AI 遇见 Flutter | 打造 500+ Widget 专属Logo
android·前端·flutter
MartinYeung51 小时前
[论文学习]动态红队测试DAS:破解医疗大语言模型静态评估的“信任陷阱”
人工智能·学习·语言模型
怕浪猫1 小时前
我用 DeepSeek + Harness 做了一个自动写代码的 Agent,效果惊人
langchain·agent·ai编程
JavaPub-rodert1 小时前
TrustGraph 详解:把知识图谱、Ontology、GraphRAG 和 AI Agent 串成一套系统
人工智能·知识图谱