【10. web 自动化测试及项目部署】:使用 skill 进行 web 自动化测试、数据库重置、项目阅读/部署文档

目录

[1. 认识 playwright-cli](#1. 认识 playwright-cli)

[1.1 什么是 MCP](#1.1 什么是 MCP)

[1.2 什么是 CLI](#1.2 什么是 CLI)

[2. 搭建 playwright-cli 环境(Windows)](#2. 搭建 playwright-cli 环境(Windows))

[2.1 安装 node.js](#2.1 安装 node.js)

[2.2 安装 opencode](#2.2 安装 opencode)

[2.3 确认浏览器版本](#2.3 确认浏览器版本)

[2.4 安装 playwright-cli](#2.4 安装 playwright-cli)

[2.5 playwright-cli 的使用](#2.5 playwright-cli 的使用)

[2.6 安装 playwright-cli skill](#2.6 安装 playwright-cli skill)

[3. 生成 web 自动化测试报告](#3. 生成 web 自动化测试报告)

[4. 构造测试数据(数据库重置)](#4. 构造测试数据(数据库重置))

[5. 开始进行自动化测试](#5. 开始进行自动化测试)

[6. 关于 LLM "降智" 的问题](#6. 关于 LLM "降智" 的问题)

[7. 小结](#7. 小结)

[8. 编写项目 README 和 DEPOLY](#8. 编写项目 README 和 DEPOLY)

[9. 项目结语](#9. 项目结语)


1. 认识 playwright-cli

playwright 是微软出品的浏览器自动化测试框架。

就是一个 python 的包,通过 python 代码的方式就可以完成浏览器的自动化测试。

github 仓库:https://github.com/microsoft/playwright

为了让 playwright 能够很好的和 LLM 结合,微软在这个基础上,做出了两种封装:

  • playwright-mcp
  • playwright-cli

1.1 什么是 MCP

MCP(ModelContextProtocol)是一套"协议规范",目的是给LLM安装上"手"。

LLM 诞生之初,用户的使用方式单纯就是通过AI工具,向LLM提问,LLM返回答案,这个过程中,LLM 能听,能说,能思考,但是不能"做"。

为了让LLM也能"做事",人们就提出了MCP

  • 用户向 AI 工具描述 "任务是啥"
  • AI 工具把 "任务描述" 和 "当前有哪些MCP Server" 信息一起告诉给LLM
  • LLM 结合任务和 MCP Server 的描述,决定给 MCP Server 发一个怎样的请求,来完成具体的任务。把这些结果统一返回给 AI 工具
  • AI 工具通过 MCP Client 按照 LLM 的返回结果,发送请求给 MCP Server
  • MCP Server 收到请求后,执行具体的任务(比如点击浏览器中的一个按钮),并返回响应给AI 工具。
  • AI 工具把得到的结果再告诉 LLM,让 LLM 进行分析。
  • LLM 分析完毕,把最终的结论返回给 AI 工具,最终再返回给用户。

1.2 什么是 CLI

CLI 全称为 Command Line Interface,也就是 "命令行界面"

ls,mkdir,rm 等指令,本质上就是 CLI 程序,opencode 也是 CLI 程序。

基于 MCP 的方式执行一个外部的任务,流程非常复杂。这就会导致整个过程消耗大量的 token,相比之下,同样是给 LLM 安装上"手",CLI 的方式就轻量很多了:

  • 用户向 AI 工具描述"任务是啥"
  • AI 工具把 "任务描述" 和 "当前有什么CLI工具" 信息一起告诉给 LLM
  • LLM 结合任务和 CLI 工具信息,生成一个具体的 CLI 命令,返回给 AI 工具。
  • AI 工具执行这个 CLI 命令,并把结果返回给 LLM 分析。
  • LLM 把分析结果返回给 AI 工具,再最终返回给用户。

目前很多大厂的产品都在进行 "CLI化",经过实测,playwright-cli 相比于playwright-mcp,token 消耗只有 1/4。

在当前的时代,token 就是成本,token 就是效率。因此 playwright-cli 是当前更好的选择,因此后续就会使用 playwright-cli 的方式进行 web 自动化测试。

2. 搭建 playwright-cli 环境(Windows)

由于我们的浏览器是运行在 windows上,因此我们需要在 windows上搭建出 playwright-cli 环境。

2.1 安装 node.js

在 windows 上安装 node.js 很简单,打开 node.js 官网,点击下载windows安装程序,下载后双击安装包安装,一路next即可

安装完成后,确保 node 和 npm 命令可用:

bash 复制代码
PS C:\Users\75060> node
Welcome to Node.js v24.18.0.
Type ".help" for more information.
>
bash 复制代码
PS C:\Users\75060> npm
npm <command>

Usage:

npm install        install all the dependencies in your project
npm install <foo>  add the <foo> dependency to your project
npm test           run this project's tests
npm run <foo>      run the script named <foo>
npm <command> -h   quick help on <command>
npm -l             display usage info for all commands
npm help <term>    search for help on <term> (in a browser)
npm help npm       more involved overview (in a browser)

All commands:

    access, adduser, approve-scripts, audit, bugs, cache, ci,
    completion, config, dedupe, deny-scripts, deprecate, diff,
    dist-tag, docs, doctor, edit, exec, explain, explore,
    find-dupes, fund, get, help, help-search, init, install,
    install-ci-test, install-test, link, ll, login, logout, ls,
    org, outdated, owner, pack, ping, pkg, prefix, profile,
    prune, publish, query, rebuild, repo, restart, root, run,
    sbom, search, set, shrinkwrap, stage, star, stars, start,
    stop, team, test, token, trust, undeprecate, uninstall,
    unpublish, unstar, update, version, view, whoami

Specify configs in the ini-formatted file:
    C:\Users\75060\.npmrc
or on the command line via: npm <command> --key=value

More configuration info: npm help config
Configuration fields: npm help 7 config

npm@11.16.0 D:\Software\Nodejs\node_modules\npm

2.2 安装 opencode

和 Linux 版本相同,使用 npm 安装

bash 复制代码
npm i -g opencode-ai

2.3 确认浏览器版本

虽然 playwright-cli 支持多种主流浏览器,但还是建议使用 chrome 最新版。

"主流浏览器" 指的是chrome,edge,firefox,safari 等。不包括国产浏览器。

国产浏览器大多是基于旧版本(可能是若干年前的版本)chrome 内核,重新包装了一套界面。

2.4 安装 playwright-cli

playwright-cli 使用 npm 安装:

bash 复制代码
npm install -g @playwright/cli@latest

当前,AI LLM 生态中的,TypeScript / node 在工程化方面占据了很重要的席位,因此我们看到的很多 AI LLM 相关工具都是基于 TypeScript /node 生态来构建的。

2.5 playwright-cli 的使用

简单的测试,如果安装成功,尝试用其打开百度主页:

bash 复制代码
palywright-cli open baidu.com --headed

--head参数非常关键。

  • 如果不加这个参数,默认会以 "无头"(headless)的方式运行 chrome,此时浏览器窗口不可见(通过隐藏窗口,降低内存占用,也防止用户操作产生干扰)。
  • 无头模式在生产级环境中更多使用,但是我们在初学阶段,还是使用 "有头" 的方式,更直观地观察到浏览器自动化执行的过程。

通过下列命令可以查看到更完整的参数选项:

bash 复制代码
playwright-cli help

这么多选项不需要我们看,也不需要我们掌握,我们只要让 AI 读取这些内容,理解 playwright-cli 的用法即可,这些固定的,繁琐的工作,能丢给 AI 的,都尽量丢给 AI

2.6 安装 playwright-cli skill

为了让 AI 可以更好的理解 playwright-cli 的用法,可以安装官方提供的 skill:

bash 复制代码
playwright-cli install --skill agents

playwright-cli 相当于一个工具箱,里面有很多工具(螺丝刀,扳手,电钻,膨胀螺丝...)

skill 则相当于是这套工具的"说明书"。(这个说明书是专门给 AI 看的)

上面这个命令执行时所在的目录,需要注意:

  • 如果是在用户目录中执行(形如C:\Users\75060),此时安装的 skill 全局有效。
  • 如果是在当前项目录中执行,此时安装的 skill 只在当前项目中生效。

这个命令的本质会在当前目录中下载对应的 skill 目录,放到 .agent 目录中。

  • 如果 .agent 是在用户目录下,则全局生效(主流 AI 工具在各个目录中,均可读取到这个skill)
  • 如果 .agent 是在项目录下,则只在当前项目中生效。

此处我选择安装在用户目录中,效果如下:

其中的 SKILL.md 就是这个 skill 的入口文档.

启动 opencode(windows 端启动),使用 /skill 命令查看当前的 skill,可以看到 plawright-cli skill已经安装成功。

3. 生成 web 自动化测试报告

回到 Linux 中的 opencode,让其生成一套 web 自动化的测试流程

根据 @SPEC.md 设计一套 web ui 测试用例,baseurl 为 http://虚拟机ip:端口号(如8080)/

结果生成到 web_testcase.md 中.

html 复制代码
# OJ 系统 Web 自动化测试文档

## 1. 测试概述

### 1.1 测试目标
对 OJ 在线判题系统的前端功能进行全面的 Web 自动化测试,确保系统各项功能正常运行。

### 1.2 测试环境
- **服务器地址**: `http://192.168.26.132:8080`
- **浏览器**: Chrome / Firefox / Edge
- **测试框架**: Playwright
- **管理员账户**: 用户名 `admin` / 密码 `vr.666666`

### 1.3 测试范围
| 模块 | 测试内容 |
|------|----------|
| 认证模块 | 登录、注册、用户名唯一性校验、退出登录 |
| 题目模块 | 题目列表、题目筛选、题目详情 |
| 判题模块 | 代码提交、判题结果展示 |
| 管理后台 | 题目增删改查、测试用例配置 |
| 落地页 | 大屏展示、数据统计展示、导航链接 |

---

## 2. 测试用例详细设计

### 2.1 认证模块

#### TC-001: 用户登录成功
| 项目 | 内容 |
|------|------|
| **用例ID** | TC-001 |
| **用例名称** | 用户登录成功 |
| **前置条件** | 用户已注册(普通用户或管理员) |
| **测试步骤** | 1. 打开登录页面 `http://192.168.26.132:8080/login.html`<br>2. 输入有效的用户名和密码<br>3. 点击登录按钮 |
| **预期结果** | 1. 登录按钮显示 loading 状态<br>2. 登录成功后页面跳转到首页<br>3. 导航栏显示当前用户名<br>4. 页面无报错信息 |
| **测试数据** | 普通用户: `testuser` / `test123456`<br>管理员: `admin` / `vr.666666` |

#### TC-002: 用户登录失败 - 用户名错误
| 项目 | 内容 |
|------|------|
| **用例ID** | TC-002 |
| **用例名称** | 用户登录失败-用户名错误 |
| **测试步骤** | 1. 打开登录页面<br>2. 输入不存在的用户名<br>3. 输入任意密码<br>4. 点击登录按钮 |
| **预期结果** | 1. 显示错误提示"用户名或密码错误"<br>2. 输入框保持不变,可重新输入<br>3. 页面不跳转 |

#### TC-003: 用户登录失败 - 密码错误
| 项目 | 内容 |
|------|------|
| **用例ID** | TC-003 |
| **用例名称** | 用户登录失败-密码错误 |
| **测试步骤** | 1. 打开登录页面<br>2. 输入已注册的用户名<br>3. 输入错误的密码<br>4. 点击登录按钮 |
| **预期结果** | 1. 显示错误提示"用户名或密码错误"<br>2. 输入框保持不变 |

#### TC-004: 用户登录 - 表单验证
| 项目 | 内容 |
|------|------|
| **用例ID** | TC-004 |
| **用例名称** | 用户登录-表单验证 |
| **测试步骤** | 1. 打开登录页面<br>2. 不输入任何内容,直接点击登录<br>3. 验证空用户名提示<br>4. 输入用户名,不输入密码,点击登录<br>5. 验证空密码提示 |
| **预期结果** | 1. 空用户名: 显示"用户名不能为空"<br>2. 空密码: 显示"密码不能为空" |

#### TC-005: 用户注册成功
| 项目 | 内容 |
|------|------|
| **用例ID** | TC-005 |
| **用例名称** | 用户注册成功 |
| **前置条件** | 测试用户名不存在 |
| **测试步骤** | 1. 打开注册页面 `http://192.168.26.132:8080/register.html`<br>2. 生成唯一用户名 `newuser_${Date.now()}`<br>3. 输入密码 `test123456`<br>4. 再次输入相同密码确认<br>5. 点击注册按钮 |
| **预期结果** | 1. 显示注册成功提示<br>2. 1.5秒后自动跳转到登录页面 |
| **测试数据** | 用户名: `newuser_${Date.now()}`(动态生成)/ 密码: `test123456` |
| **可重复执行** | 是,每次使用唯一用户名 |

#### TC-006: 用户注册 - 用户名已存在
| 项目 | 内容 |
|------|------|
| **用例ID** | TC-006 |
| **用例名称** | 用户注册-用户名已存在 |
| **前置条件** | 用户 `admin` 必须存在 |
| **测试步骤** | 1. 打开注册页面<br>2. 输入已存在的用户名 `admin`<br>3. 等待用户名唯一性检查(自动检测)<br>4. 输入密码和确认密码<br>5. 点击注册按钮 |
| **预期结果** | 1. 显示用户名已被占用的错误提示<br>2. 注册按钮不可点击或提交被拒绝 |
| **可重复执行** | 是,`admin` 为预置管理员账户不会被删除 |

#### TC-007: 用户注册 - 密码不一致
| 项目 | 内容 |
|------|------|
| **用例ID** | TC-007 |
| **用例名称** | 用户注册-密码不一致 |
| **测试步骤** | 1. 打开注册页面<br>2. 输入有效用户名<br>3. 输入密码 `test123456`<br>4. 输入不同的确认密码 `test1234567`<br>5. 点击注册按钮 |
| **预期结果** | 1. 显示"两次输入的密码不一致"错误提示 |

#### TC-008: 用户注册 - 用户名格式验证
| 项目 | 内容 |
|------|------|
| **用例ID** | TC-008 |
| **用例名称** | 用户注册-用户名格式验证 |
| **测试步骤** | 分别测试以下用户名格式:<br>1. 空用户名<br>2. 用户名少于3字符: `ab`<br>3. 用户名超过20字符<br>4. 用户名包含特殊字符: `user@name`<br>5. 有效用户名: `valid_user123` |
| **预期结果** | 1. 空: "用户名不能为空"<br>2. 少于3字符: "用户名至少需要3个字符"<br>3. 超过20字符: "用户名最多20个字符"<br>4. 特殊字符: "用户名只能包含字母、数字和下划线"<br>5. 有效格式: 通过验证 |

#### TC-009: 用户注册 - 密码长度验证
| 项目 | 内容 |
|------|------|
| **用例ID** | TC-009 |
| **用例名称** | 用户注册-密码长度验证 |
| **测试步骤** | 分别测试以下密码:<br>1. 空密码<br>2. 密码少于6字符: `12345`<br>3. 密码超过50字符<br>4. 有效密码: `test123456` |
| **预期结果** | 1. 空: "密码不能为空"<br>2. 少于6字符: "密码至少需要6个字符"<br>3. 超过50字符: "密码最多50个字符"<br>4. 有效长度: 通过验证 |

#### TC-010: 用户退出登录
| 项目 | 内容 |
|------|------|
| **用例ID** | TC-010 |
| **用例名称** | 用户退出登录 |
| **前置条件** | 用户已登录 |
| **测试步骤** | 1. 用户已登录状态<br>2. 点击导航栏的"退出登录"按钮 |
| **预期结果** | 1. 清除用户 session<br>2. 页面跳转到登录页面<br>3. 尝试直接访问题目列表会被重定向到登录页 |

#### TC-011: 未登录用户访问受保护页面
| 项目 | 内容 |
|------|------|
| **用例ID** | TC-011 |
| **用例名称** | 未登录用户访问受保护页面 |
| **测试步骤** | 1. 清除所有登录状态(清除 cookies/localStorage)<br>2. 直接访问 `http://192.168.26.132:8080/problem_list.html`<br>3. 直接访问 `http://192.168.26.132:8080/admin/admin.html` |
| **预期结果** | 1. 页面自动重定向到登录页面 |

---

### 2.2 题目模块

#### TC-012: 题目列表展示
| 项目 | 内容 |
|------|------|
| **用例ID** | TC-012 |
| **用例名称** | 题目列表展示 |
| **前置条件** | 用户已登录 |
| **测试步骤** | 1. 登录系统<br>2. 进入题目列表页面 |
| **预期结果** | 1. 页面正确显示题目列表<br>2. 每道题目显示: 题号、标题、难度、时间限制、内存限制<br>3. 难度使用不同颜色标识(简单-绿色/中等-黄色/困难-红色) |

#### TC-013: 题目列表筛选 - 按难度
| 项目 | 内容 |
|------|------|
| **用例ID** | TC-013 |
| **用例名称** | 题目列表筛选-按难度 |
| **前置条件** | 系统中存在不同难度的题目 |
| **测试步骤** | 1. 在题目列表页面<br>2. 点击"全部"筛选按钮<br>3. 点击"简单"筛选按钮<br>4. 点击"中等"筛选按钮<br>5. 点击"困难"筛选按钮 |
| **预期结果** | 1. 点击后按钮高亮显示<br>2. 列表只显示对应难度的题目<br>3. 切换筛选条件后列表正确更新 |

#### TC-014: 题目列表为空状态
| 项目 | 内容 |
|------|------|
| **用例ID** | TC-014 |
| **用例名称** | 题目列表为空状态 |
| **前置条件** | 数据库中没有题目 |
| **测试步骤** | 进入题目列表页面 |
| **预期结果** | 显示"暂无题目"提示和空状态图标 |

#### TC-015: 题目详情展示
| 项目 | 内容 |
|------|------|
| **用例ID** | TC-015 |
| **用例名称** | 题目详情展示 |
| **前置条件** | 系统中存在题目 |
| **测试步骤** | 1. 在题目列表点击某道题目<br>2. 进入题目详情页面 |
| **预期结果** | 1. 页面正确显示题目标题<br>2. 显示难度标签<br>3. 显示时间限制和内存限制<br>4. 显示完整的题目描述<br>5. 显示示例输入/输出(如有) |

#### TC-016: 代码编辑器功能
| 项目 | 内容 |
|------|------|
| **用例ID** | TC-016 |
| **用例名称** | 代码编辑器功能 |
| **前置条件** | 进入题目详情页面 |
| **测试步骤** | 1. 确认代码编辑器加载成功<br>2. 在编辑器中输入代码 `cout << "Hello";`<br>3. 切换语言为 Python<br>4. 确认编辑器内容变化 |
| **预期结果** | 1. Ace 编辑器正常加载<br>2. 代码可正常输入<br>3. 切换语言后,代码模板更新 |

---

### 2.3 判题模块

#### TC-017: 代码提交成功 - 答案正确
| 项目 | 内容 |
|------|------|
| **用例ID** | TC-017 |
| **用例名称** | 代码提交成功-答案正确 |
| **前置条件** | 存在一道简单题目及其测试用例 |
| **测试步骤** | 1. 进入某道题目的详情页<br>2. 输入正确答案的代码<br>3. 点击"提交代码"按钮<br>4. 等待判题结果 |
| **预期结果** | 1. 按钮显示"提交中..."状态<br>2. 显示"判题中..."状态<br>3. 判题完成后显示绿色"通过"状态<br>4. 显示执行时间 |
| **测试数据** | 示例:两数相加题目 |

#### TC-018: 代码提交 - 答案错误
| 项目 | 内容 |
|------|------|
| **用例ID** | TC-018 |
| **用例名称** | 代码提交-答案错误 |
| **测试步骤** | 1. 进入题目详情页<br>2. 输入错误答案的代码<br>3. 提交代码 |
| **预期结果** | 1. 显示红色"答案错误"状态<br>2. 不显示执行时间或显示实际时间 |

#### TC-019: 代码提交 - 编译错误
| 项目 | 内容 |
|------|------|
| **用例ID** | TC-019 |
| **用例名称** | 代码提交-编译错误 |
| **测试步骤** | 1. 进入题目详情页<br>2. 输入有语法错误的代码(如 `#include <iostream>` 写成 `#include <iostream>` 但语法错误)<br>3. 提交代码 |
| **预期结果** | 1. 显示紫色"编译错误"状态<br>2. 显示具体的编译错误信息 |

#### TC-020: 代码提交 - 运行错误
| 项目 | 内容 |
|------|------|
| **用例ID** | TC-020 |
| **用例名称** | 代码提交-运行错误 |
| **测试步骤** | 1. 进入题目详情页<br>2. 输入会触发运行时错误的代码(如除零错误、数组越界)<br>3. 提交代码 |
| **预期结果** | 1. 显示粉色"运行错误"状态<br>2. 显示运行时错误信息 |

#### TC-021: 代码提交 - 超时
| 项目 | 内容 |
|------|------|
| **用例ID** | TC-021 |
| **用例名称** | 代码提交-超时 |
| **测试步骤** | 1. 进入题目详情页<br>2. 输入包含无限循环的代码<br>3. 提交代码 |
| **预期结果** | 1. 显示橙色"超时"状态<br>2. 不显示执行时间或显示超时提示 |

#### TC-022: 判题结果轮询
| 项目 | 内容 |
|------|------|
| **用例ID** | TC-022 |
| **用例名称** | 判题结果轮询 |
| **测试步骤** | 1. 提交代码后<br>2. 观察页面状态变化<br>3. 等待最终结果 |
| **预期结果** | 1. 每秒自动刷新判题状态<br>2. 状态从"判题中"变为最终结果<br>3. 轮询在获得最终结果后自动停止 |

#### TC-023: 空代码提交
| 项目 | 内容 |
|------|------|
| **用例ID** | TC-023 |
| **用例名称** | 空代码提交 |
| **测试步骤** | 1. 进入题目详情页<br>2. 不输入任何代码<br>3. 点击提交按钮 |
| **预期结果** | 1. 弹出提示"请输入代码"或类似提示<br>2. 不发送提交请求 |

---

### 2.4 管理后台模块

#### TC-024: 管理员访问管理后台
| 项目 | 内容 |
|------|------|
| **用例ID** | TC-024 |
| **用例名称** | 管理员访问管理后台 |
| **前置条件** | 使用管理员账户登录 |
| **测试步骤** | 1. 使用管理员账号 `admin` / `vr.666666` 登录<br>2. 自动跳转或手动进入管理后台 |
| **预期结果** | 1. 成功进入管理后台<br>2. 显示"题目管理"标题<br>3. 显示"新增题目"按钮 |

#### TC-025: 普通用户禁止访问管理后台
| 项目 | 内容 |
|------|------|
| **用例ID** | TC-025 |
| **用例名称** | 普通用户禁止访问管理后台 |
| **前置条件** | 使用普通用户账户登录 |
| **测试步骤** | 1. 使用普通用户账号登录<br>2. 尝试访问 `http://192.168.26.132:8080/admin/admin.html` |
| **预期结果** | 1. 显示无权限提示<br>2. 自动跳转到题目列表页面 |

#### TC-026: 创建新题目
| 项目 | 内容 |
|------|------|
| **用例ID** | TC-026 |
| **用例名称** | 创建新题目 |
| **前置条件** | 管理员已登录 |
| **测试步骤** | 1. 进入管理后台<br>2. 点击"新增题目"按钮<br>3. 生成唯一标题: `测试题目_${Date.now()}`<br>4. 填写题目描述: "给定两个整数,返回它们的和"<br>5. 选择难度: 简单<br>6. 时间限制: 1000ms<br>7. 内存限制: 256MB<br>8. 添加测试用例: 输入 "1 2" 输出 "3"<br>9. 点击"创建"按钮 |
| **预期结果** | 1. 弹出新增题目模态框<br>2. 题目创建成功后显示"创建成功"提示<br>3. 模态框关闭<br>4. 题目列表更新显示新题目 |
| **测试数据** | 标题: `测试题目_${Date.now()}`(动态生成)<br>描述: `给定两个整数,返回它们的和`<br>难度: `easy`<br>时间限制: `1000`<br>内存限制: `256`<br>测试用例: 输入 `1 2` 输出 `3` |
| **可重复执行** | 是,每次使用唯一标题 |

#### TC-027: 编辑题目
| 项目 | 内容 |
|------|------|
| **用例ID** | TC-027 |
| **用例名称** | 编辑题目 |
| **前置条件** | 系统中存在至少一道题目 |
| **测试步骤** | 1. 进入管理后台<br>2. **先创建一个测试题目**(标题: `测试题目编辑_${Date.now()}`)<br>3. 点击该题目的"编辑"按钮<br>4. 修改题目标题<br>5. 修改题目描述<br>6. 点击"保存"按钮 |
| **预期结果** | 1. 弹出编辑题目模态框<br>2. 表单预填充当前题目信息<br>3. 保存成功后显示"更新成功"提示<br>4. 题目列表中显示更新后的信息 |
| **可重复执行** | 是,使用动态生成的唯一标题 |

#### TC-028: 删除题目
| 项目 | 内容 |
|------|------|
| **用例ID** | TC-028 |
| **用例名称** | 删除题目 |
| **前置条件** | 管理员已登录 |
| **测试步骤** | 1. 进入管理后台<br>2. **先创建一个测试题目**(标题: `测试题目删除_${Date.now()}`)<br>3. 点击该题目的"删除"按钮<br>4. 在确认弹窗中点击"确定" |
| **预期结果** | 1. 弹出确认对话框"确定要删除这道题目吗?"<br>2. 确认后显示"删除成功"提示<br>3. 题目从列表中移除 |
| **可重复执行** | 是,使用动态生成的唯一标题,删除自己创建的数据 |

#### TC-029: 取消删除题目
| 项目 | 内容 |
|------|------|
| **用例ID** | TC-029 |
| **用例名称** | 取消删除题目 |
| **前置条件** | 管理员已登录 |
| **测试步骤** | 1. 进入管理后台<br>2. **先创建一个测试题目**(标题: `测试题目取消删除_${Date.now()}`)<br>3. 点击该题目的"删除"按钮<br>4. 在确认弹窗中点击"取消" |
| **预期结果** | 1. 确认对话框关闭<br>2. 题目未被删除<br>3. 题目列表保持不变 |
| **可重复执行** | 是,使用动态生成的唯一标题,删除自己创建的数据 |

#### TC-030: 添加多个测试用例
| 项目 | 内容 |
|------|------|
| **用例ID** | TC-030 |
| **用例名称** | 添加多个测试用例 |
| **前置条件** | 进入新增/编辑题目模态框 |
| **测试步骤** | 1. 打开新增或编辑题目模态框<br>2. 点击"添加"按钮添加测试用例<br>3. 添加 3 个测试用例 |
| **预期结果** | 1. 成功添加多个测试用例字段<br>2. 可以分别填写每个用例的输入和预期输出<br>3. 可以单独删除某个测试用例 |

#### TC-031: 创建题目 - 表单验证
| 项目 | 内容 |
|------|------|
| **用例ID** | TC-031 |
| **用例名称** | 创建题目-表单验证 |
| **测试步骤** | 1. 进入管理后台<br>2. 点击"新增题目"按钮<br>3. 不填写任何内容,直接点击"创建" |
| **预期结果** | 1. 显示"请填写完整信息"错误提示<br>2. 不会发送创建请求 |

#### TC-032: 题目列表显示验证
| 项目 | 内容 |
|------|------|
| **用例ID** | TC-032 |
| **用例名称** | 题目列表显示验证 |
| **前置条件** | 系统中存在多道不同难度的题目 |
| **测试步骤** | 在管理后台查看题目列表 |
| **预期结果** | 1. 表格显示: ID、标题、难度、时间限制、操作<br>2. 操作列有"编辑"和"删除"两个按钮<br>3. 难度使用正确的颜色标识 |

---

### 2.5 页面 UI 测试

#### TC-033: 登录页面样式验证
| 项目 | 内容 |
|------|------|
| **用例ID** | TC-033 |
| **用例名称** | 登录页面样式验证 |
| **测试步骤** | 打开登录页面并检查 |
| **预期结果** | 1. 深色主题背景 (#0F172A)<br>2. 居中的登录卡片<br>3. 绿色主题按钮 (#22C55E)<br>4. 输入框有正确的 focus 效果<br>5. 页面有赛博朋克风格的网格背景 |

#### TC-034: 响应式布局测试
| 项目 | 内容 |
|------|------|
| **用例ID** | TC-034 |
| **用例名称** | 响应式布局测试 |
| **测试步骤** | 1. 在桌面浏览器(1920px)查看页面<br>2. 调整浏览器窗口到平板尺寸(768px)<br>3. 调整到手机尺寸(375px) |
| **预期结果** | 1. 桌面: 题目列表显示完整的表格列<br>2. 平板/手机: 表格列自适应,题目卡片式展示<br>3. 导航栏自适应显示 |

#### TC-035: 页面加载状态
| 项目 | 内容 |
|------|------|
| **用例ID** | TC-035 |
| **用例名称** | 页面加载状态 |
| **测试步骤** | 1. 刷新题目列表页面<br>2. 刷新题目详情页面 |
| **预期结果** | 1. 显示 loading 状态(spinner)<br>2. 数据加载完成后显示实际内容 |

---

### 2.6 落地页模块

#### TC-036: 落地页展示
| 项目 | 内容 |
|------|------|
| **用例ID** | TC-036 |
| **用例名称** | 落地页展示 |
| **测试步骤** | 1. 打开落地页 `http://192.168.26.132:8080/index.html`<br>2. 检查页面核心元素 |
| **预期结果** | 1. 页面正常加载,无报错<br>2. 显示 OJ 系统标题/Logo<br>3. 显示统计数据(题目数量、用户数量、提交次数等)<br>4. 深色主题背景 |

#### TC-037: 落地页导航链接 - 登录
| 项目 | 内容 |
|------|------|
| **用例ID** | TC-037 |
| **用例名称** | 落地页导航链接-登录 |
| **测试步骤** | 1. 在落地页点击"登录"按钮 |
| **预期结果** | 1. 页面跳转到登录页面 `http://192.168.26.132:8080/login.html` |

#### TC-038: 落地页导航链接 - 注册
| 项目 | 内容 |
|------|------|
| **用例ID** | TC-038 |
| **用例名称** | 落地页导航链接-注册 |
| **测试步骤** | 1. 在落地页点击"注册"按钮 |
| **预期结果** | 1. 页面跳转到注册页面 `http://192.168.26.132:8080/register.html` |

#### TC-039: 落地页导航链接 - 题目列表
| 项目 | 内容 |
|------|------|
| **用例ID** | TC-039 |
| **用例名称** | 落地页导航链接-题目列表 |
| **测试步骤** | 1. 在落地页点击"开始刷题"或题目列表入口 |
| **预期结果** | 1. 未登录时:跳转登录页面<br>2. 已登录时:跳转题目列表页面 |

#### TC-040: 落地页大屏展示效果
| 项目 | 内容 |
|------|------|
| **用例ID** | TC-040 |
| **用例名称** | 落地页大屏展示效果 |
| **测试步骤** | 1. 在桌面浏览器(1920px)打开落地页<br>2. 检查页面布局和视觉效果 |
| **预期结果** | 1. 统计数据以大字号展示<br>2. 页面布局大气、居中<br>3. 背景样式符合赛博朋克/深色主题风格 |

---

## 3. 测试执行流程

### 3.1 环境准备
```bash
# 安装 Playwright
npm install -D @playwright/test
npx playwright install chromium
```

### 3.2 测试脚本结构
```
tests/
└── e2e/
    ├── config.js          # 测试配置
    ├── login.spec.js      # 登录相关测试
    ├── register.spec.js  # 注册相关测试
    ├── problems.spec.js  # 题目相关测试
    ├── submit.spec.js    # 判题相关测试
    ├── admin.spec.js     # 管理后台测试
    └── landing.spec.js   # 落地页测试
```

### 3.3 测试配置示例
```javascript
// playwright.config.js
module.exports = {
  testDir: './tests/e2e',
  timeout: 30000,
  retries: 1,
  use: {
    baseURL: 'http://192.168.26.132:8080',
    headless: true,
    screenshot: 'only-on-failure',
    video: 'retain-on-failure',
  },
  projects: [
    { name: 'chromium', use: { browserName: 'chromium' } },
    { name: 'firefox', use: { browserName: 'firefox' } },
  ],
};
```

### 3.4 测试执行命令
```bash
# 运行所有测试
npx playwright test

# 运行特定测试文件
npx playwright test tests/e2e/login.spec.js

# 运行特定标签的测试
npx playwright test --grep "登录"

# 生成测试报告
npx playwright test --reporter=html
```

---

## 4. 测试数据准备

### 4.1 预置测试用户
| 用户名 | 密码 | 角色 | 用途 |
|--------|------|------|------|
| admin | vr.666666 | 管理员 | 管理后台测试 |
| testuser | test123456 | 普通用户 | 普通用户功能测试 |

### 4.2 预置测试题目
| 题号 | 标题 | 难度 | 描述 |
|------|------|------|------|
| 1 | 两数之和 | easy | 给定两个整数,返回它们的和 |
| 2 | 反转字符串 | medium | 给定一个字符串,返回它的反转 |
| 3 | 质数判定 | hard | 判断一个数是否为质数 |

---

## 5. 缺陷跟踪

### 5.1 缺陷严重等级
| 等级 | 说明 |
|------|------|
| P0 | 系统崩溃,无法继续测试 |
| P1 | 核心功能无法使用 |
| P2 | 功能有缺陷,但有替代方案 |
| P3 | UI/UX 问题,不影响功能 |

### 5.2 缺陷记录表
| 缺陷ID | 用例ID | 描述 | 严重等级 | 状态 |
|--------|--------|------|----------|------|
| - | - | - | - | - |

---

## 6. 附录

### 6.1 API 端点参考
| 方法 | 端点 | 描述 |
|------|------|------|
| POST | /api/auth/register | 注册 |
| POST | /api/auth/login | 登录 |
| GET | /api/problems | 题目列表 |
| GET | /api/problems/:id | 题目详情 |
| POST | /api/admin/problems | 创建题目 |
| PUT | /api/admin/problems/:id | 更新题目 |
| DELETE | /api/admin/problems/:id | 删除题目 |
| POST | /api/submit | 提交代码 |
| GET | /api/submissions/:id | 提交详情 |

### 6.2 判题状态说明
| 状态 | 显示 | 说明 |
|------|------|------|
| pending | 判题中 | 等待判题 |
| accepted | 通过 | 答案正确 |
| wrong_answer | 答案错误 | 输出结果不符 |
| time_limit_exceeded | 超时 | 超出时间限制 |
| runtime_error | 运行错误 | 程序运行时崩溃 |
| compile_error | 编译错误 | 代码编译失败 |

---

*文档版本: v1.0*
*创建日期: 2026-07-22*

4. 构造测试数据(数据库重置)

虽然测试用例文档已经有了,但是还不能直接开始测试,测试能通过,功能能正确,取决于两方面:

  • 代码逻辑正确
  • 数据库中的数据正确

要想验证代码逻辑,需要先保证数据库中,有正确的代码。

由于前面已经进行了多轮单元测试和接口自动化测试,数据库中已经有很多"测试数据"。这些数据可能就对接下来的测试造成负面干扰,因此需要先确保数据库是"干净"的,把冗余数据删除掉,只保留需要的数据,这个过程不需要手动完成,可以让 AI 写一个工具,完成**"数据库重置工作"** 。

@SEPC.md @web自动化测试文档.md 根据 web 自动化测试文档,编写一个程序(C++),实现对数据库进行重置的效果,删除数据库中的冗余的内容,构造接口自动化需要的必要数据.

注意:数据库充值程序是一个很危险的程序,一定要确认好,你操作的数据库确实是可以删除的。千万不要在生产环境上运行这个程序.

5. 开始进行自动化测试

将项目使用 git 提交至仓库,然后在 windows 端进行克隆:

bash 复制代码
git clone 仓库链接

在克隆下来的项目中打开 opencode

使用 skill 并结合 web自动化测试文档

测试用例比较多,直接一口气执行,时间长且可能不稳定,所以可以分批次的执行

/playwright-cli @web自动化测试文档.md 根据文档描述,使用有头模式(--headed),完成 web 自动化测试,每个操作之间停顿 1 秒,方便我进行观察,先进行 xx~xx 测试用例的执行.

opencode 执行的过程中是有 bug 的,opencode 进行 web 自动化测试的时候,打开网页然后就卡住了,我们需要手动暂停任务(esc 按两次),然后说:

继续执行

对于上述测试用例来说,初次执行通常不会很顺利,需要有一个"探索"的过程。

当用例最终通过之后,可以让 AI 把执行步骤总结成文档,这样后续再执行,直接按照总结好的文档来进行操作即可。

将上述执行过程,总结到 @web自动化测试文档-playwright-cli.md

针对出现问题,AI 反复尝试无法解决的情况,我们应该引导 AI,如:

@public/problem.html 当前针对提交的代码出错的情况(编译错误,运行出错,运行超时),此时后端通过接口测试,已经验证了服务器返回了出错的详细情况 @tests/python/test_api.py(接口测试代码参见这个文件),对应的后端代码参见 @src/handler/submit_handler.cc。但是前端页面上没有展示出具体出错的详细信息,确认这个问题,并修改。

6. 关于 LLM "降智" 的问题

在项目的后期,能明显感觉到 LLM 似乎开始 "降智" 了。

这种情况在 LLM 中是比较普遍的情况。一个 LLM 的 "智商" 是和供应商提供的 "算力" 是直接相关的。

一个新模型上线之初,用户量少,此时单位请求能够使用的算力就更多,模型能力就更强;随着用户量逐渐增加,如果服务商没有对算力进行扩容,那么单个请求使用的算力可能会大幅度减少,从而出现 "降智"。

大家在学习阶段,一定是选择合适的模型。

7. 小结

通过上面的一系列操作,我们就完成了web自动化测试的整个过程。

  • 技术上基于 playwright-cli 实现浏览器操作
  • 测试之前,需要先根据项目代码,梳理出一个初步的测试文档。
  • 每一次都执行文档中的一部分用例,来 "趟一遍坑"。
  • 完成初次测试之后,可以把具体操作步骤总结下来,填写到另一个文档中。
  • 针对不通过的用例,可以单独执行这个用例,进一步分析和解决问题。
  • 所有用例都 "趟完一遍" 之后,可以根据总结出的文档,再次进行测试,进一步验证。

8. 编写项目 README 和 DEPOLY

一个开源项目通常都需要有介绍文档和一个部署文档。我们可以让 AI 帮我们生成文档,使项目看起来 "更专业"。

@SEPC.md 根据文档描述和代码仓库内容,编写 DEPOLY.md(项目部署文档)和 README.md(项目介绍文档)

AI 完成文档编写后,可以尝试找一台新机器(云服务器)进行从头部署,看看是否可行,其中可能会遇到很多问题,比如依赖/库无法下载(可能 AI 是从 github 上下载,不想 FQ 可以让 AI 进行修改)

9. 项目结语

到这一步,本项目完结撒花。

通过上面的学习过程,我们不光学习项目本身,更重要的是学习理解 Vibe Coding 这种新时代的开发方式。

目前来看,无论是大公司还是中小公司,都把 Vibe Coding 作为非常重要的推进点,因为 AI 确实能帮助我们大幅度提高代码开发效率。

另一方面,大家掌握了 Vibe Coding 这一项技能之后,还可以基于 Vibe Coding 重构自己做过的其他项目,或者基于 Vibe Coding 开发任何你想做的新项目。天高海阔,任由各位自由发挥。

相关推荐
REDcker5 天前
Cesium三维WebGIS入门详解
前端·gis·web·cesium·webgis
罗超驿6 天前
JavaEE进阶之路:从Web架构原理到HTML标签全解析
前端·html·web·javaee
DogDaoDao6 天前
OpenBrowser 深度解析:让 AI 真正「用上」浏览器的自主代理框架
人工智能·程序员·大模型·github·web·ai工具·openbrowser
jieyucx10 天前
Nuxt4阶段六:工程化与进阶 —— 模块、中间件、插件、TS 与测试
中间件·vue·web·nuxt·全栈·ssr
jieyucx12 天前
Nuxt阶段二:核心概念 —— 路由、布局、组件与 Composables
vue·web·nuxt·全栈·seo·ssr
kali-Myon13 天前
深入 MySQL 内核:从临时哈希表分配机制详解 Floor 报错注入核心原理
数据库·sql·mysql·安全·web
钛态15 天前
前端安全防线:CSRF 攻击链路与双重 Token 校验的工程实现
前端·vue·react·web
钛态15 天前
AI 组件生成评测:别只看页面能不能渲染
前端·vue·react·web
shuoshuohaohao18 天前
《HTTP协议》
java·web