
1. 项目概述当AI开始写测试代码最近在搞前端自动化测试的团队估计都听过或者正在用Cypress。这玩意儿确实香写出来的测试用例能像真人一样操作浏览器截图、录屏、时间旅行调试功能强大到让传统的Selenium有点“老态龙钟”。但问题也来了写Cypress测试尤其是要覆盖各种复杂交互和边缘场景的“生产级”用例依然是个技术活更是个体力活。你得懂前端、懂业务、还得懂Cypress那一套独特的异步处理和命令链。就在我们还在为测试覆盖率头疼、为维护一堆脆弱的测试脚本掉头发的时候AI大模型已经悄悄把“手”伸进了这个领域。现在一个更具体、更有想象力的玩法出现了用“技能库”Skills来武装AI让它直接写出能上生产环境的前端自动化测试代码。这不再是简单的“让AI写几行代码”而是构建一个专属于测试领域的“AI副驾驶”它理解Cypress的语法、懂得前端测试的最佳实践、甚至能记住你们项目里那些特定的页面对象和业务规则。简单说这个项目的核心就是将人类测试工程师的智慧和经验封装成一个个可复用的“技能”注入给AI助手。然后你只需要用自然语言描述测试场景比如“测试用户从商品列表页点击第一个商品加入购物车然后去结算页验证商品信息和价格”AI就能基于技能库生成结构清晰、健壮可靠、可直接集成到CI/CD流水线中的Cypress测试代码。这背后不仅仅是“AI生成代码”而是一次测试生产范式的转变。测试用例的创作从“手工作坊”走向了“标准化流水线”而工程师的角色则从重复的编码者升级为技能库的设计师、AI输出的审核员和复杂测试策略的架构师。2. 核心思路技能库如何“教会”AI写测试让AI直接写代码尤其是写测试代码最怕的就是它“天马行空”——生成的代码要么语法错误要么逻辑诡异要么完全不符合项目规范和最佳实践。这就是“技能库”要解决的根本问题。它本质上是一个高度结构化的“测试知识图谱”和“代码模板集合”用来约束和引导AI的输出确保其专业性。2.1 技能库的构成从原子操作到业务场景一个有效的Cypress测试技能库通常是分层级的就像搭积木一样从最基础的原子操作开始逐步组合成复杂的业务流。第一层原子操作技能这是最基础的技能单元对应Cypress最核心的DOM操作和断言命令。AI需要被“教会”这些技能的标准写法和最佳实践。导航技能cy.visit(‘/login’)。技能库会告诉AIurl最好用常量或配置管理并处理可能的加载超时。元素获取技能cy.get(‘[data-cysubmit-btn]’)。这是关键技能库会强制AI使用>// 原子技能示例带健壮等待的元素获取 Cypress.Commands.add(getByTestId, (testId: string, ...args) { return cy.get([data-testid${testId}], ...args).should(be.visible); }); /** * 组合技能用户登录 * param {string} username - 用户名 * param {string} password - 密码 * example * cy.login(testexample.com, password123) */ Cypress.Commands.add(login, (username: string, password: string) { cy.visit(/login); // 技能库规定导航用cy.visit且路径从配置读取 cy.getByTestId(email-input).type(username); cy.getByTestId(password-input).type(password); cy.getByTestId(login-submit-btn).click(); // 登录后验证确保登录成功 cy.url().should(include, /dashboard); cy.getByTestId(user-avatar).should(exist); });在cypress/support/e2e.ts中导入这些命令确保它们全局可用。// 导入自定义命令 import ./commands; // 全局配置也是技能 Cypress.on(uncaught:exception, (err) { // 忽略某些预期内的应用错误避免测试失败 if (err.message.includes(ResizeObserver)) { return false; } return true; });3.2 第二步抽象与封装——实现页面对象模式页面对象是让AI生成可维护代码的关键。在cypress/pages/LoginPage.ts中export class LoginPage { // 元素定位器 - 全部使用data-testid属性 elements { emailInput: () cy.getByTestId(email-input), passwordInput: () cy.getByTestId(password-input), submitButton: () cy.getByTestId(login-submit-btn), errorMessage: () cy.getByTestId(login-error-message), }; // 页面动作 - AI可以直接调用的方法 /** * 访问登录页 */ visit() { cy.visit(/login); return this; } /** * 填写登录表单 * param email 邮箱 * param password 密码 */ fillForm(email: string, password: string) { this.elements.emailInput().clear().type(email); this.elements.passwordInput().clear().type(password); return this; } /** * 提交登录表单 */ submit() { this.elements.submitButton().click(); return this; } /** * 执行完整登录流程 * param email 邮箱 * param password 密码 */ login(email: string, password: string) { this.visit().fillForm(email, password).submit(); } }3.3 第三步提供范例——编写高质量的示例测试技能库需要“教学案例”。在cypress/e2e/examples/目录下提供几个典范级的测试文件。AI会极大地参考这些文件的风格和模式。// cypress/e2e/examples/login.spec.ts import { LoginPage } from ../../pages/LoginPage; describe(用户登录流程, () { const loginPage new LoginPage(); const validUser { email: testexample.com, password: securePass123 }; const invalidUser { email: wrongexample.com, password: wrong }; beforeEach(() { // 每个测试前都从首页开始确保状态干净 cy.visit(/); }); it(使用有效凭证登录应跳转到仪表盘, () { // AI应学会这种“页面对象自定义命令”的混合风格 loginPage.login(validUser.email, validUser.password); cy.url().should(include, /dashboard); cy.getByTestId(welcome-message).should(contain, validUser.email); }); it(使用无效凭证登录应显示错误信息, () { loginPage.login(invalidUser.email, invalidUser.password); // AI应学会验证负面场景 loginPage.elements.errorMessage() .should(be.visible) .and(contain, 用户名或密码错误); cy.url().should(eq, Cypress.config().baseUrl /login); // 应停留在登录页 }); it(表单验证邮箱格式错误应有提示, () { loginPage.visit().fillForm(invalid-email, anypass).submit(); // AI应学会更精细的表单验证断言 cy.getByTestId(email-input).then(($input) { expect($input[0].validationMessage).to.include(请输入有效的电子邮件地址); }); }); });3.4 第四步集成与提示——配置你的AI助手现在将你的技能库“喂”给AI。以目前流行的Cursor IDE为例在项目根目录创建.cursor/rules/cypress-test.mdc文件。这是一个给Cursor AI的规则文件。在规则文件中用自然语言清晰地描述你的技能库规范# Cypress 测试生成规范 ## 核心原则 - 所有测试必须使用 **TypeScript**。 - 元素选择**必须**使用 data-testid 属性并通过 cy.getByTestId 命令获取。 - 优先使用 **页面对象模式**。页面类位于 cypress/pages/。 - 常用操作如登录使用 cypress/support/commands.ts 中定义的**自定义命令**。 ## 代码结构 - 使用 describe 描述功能模块it 描述具体用例。 - 每个 it 用例应独立、原子化。 - 使用 beforeEach 进行通用准备afterEach 进行清理。 ## 断言与等待 - 避免使用 cy.wait(毫秒数) 进行硬等待。 - 使用 .should() 进行链式断言等待元素状态。 - 对于网络请求使用 cy.intercept() 进行监听和断言。 ## 示例参考 请参考 cypress/e2e/examples/ 目录下的测试文件风格。 ## 禁止事项 - 禁止使用 .then() 进行复杂的逻辑串联优先使用Cypress命令链。 - 禁止使用脆弱的CSS选择器如 :nth-child()、.btn-primary除非有唯一性保证。当你用Cursor的Chat功能或“/”指令生成测试代码时它会自动参考这份规则和你的项目上下文已打开的文件生成符合你技能库规范的代码。实操心得技能库的构建是一个迭代过程。不要试图一次性定义所有技能。从你最常测试的1-2个核心流程开始比如登录、下单创建对应的页面对象和自定义命令并写好示例。然后让AI尝试生成这些流程的测试根据它的“错误”和“偏差”不断补充和修正你的技能库文档和示例。这个过程本身就是在沉淀团队的测试知识。4. 生成代码解析AI如何写出生产级测试假设我们现在有一个需求“测试将商品加入购物车后购物车图标上的数量徽章应该更新”。我们把这条指令连同我们构建的技能库上下文一起交给AI如Cursor。4.1 AI的思考与输出过程AI会基于技能库进行以下“思考”识别实体“商品”、“加入购物车按钮”、“购物车图标”、“数量徽章”。技能库告诉它这些元素都应该有>// AI生成的代码添加商品到购物车测试 import { ProductListPage } from ../pages/ProductListPage; import { HeaderComponent } from ../components/HeaderComponent; // 假设我们有Header组件对象 describe(购物车功能, () { const productListPage new ProductListPage(); const header new HeaderComponent(); beforeEach(() { // 技能库规定从首页开始并确保用户已登录如果需要 cy.visit(/); // 如果该功能需要登录AI会调用自定义命令 // cy.login(Cypress.env(testUser), Cypress.env(testPass)); }); it(将商品加入购物车后购物车徽章数量应增加, () { // 1. 导航到商品列表页假设有导航 cy.getByTestId(nav-products).click(); // 2. 获取第一个商品的“加入购物车”按钮并点击 // AI使用了页面对象的方法这是技能库鼓励的 productListPage.getFirstProductAddToCartButton().click(); // 3. 监听加入购物车的API请求确保操作完成高级技能 cy.intercept(POST, **/api/cart/items).as(addToCart); cy.wait(addToCart).its(response.statusCode).should(eq, 200); // 4. 断言头部购物车图标上的徽章数字变为1 header.getCartBadgeCount().should(have.text, 1); // 或者如果徽章初始隐藏新增后应显示 header.getCartBadge().should(be.visible).and(contain, 1); }); });4.2 代码质量评估与人工润色AI生成的这段代码已经具备了生产级测试的雏形结构规范符合describe/it结构使用了beforeEach。元素定位可靠通过页面对象和方法调用避免了裸漏的选择器。包含等待逻辑使用了cy.intercept和cy.wait来确保异步操作完成这是编写稳定测试的关键。断言明确验证了徽章的文本内容。但作为资深测试我们还需要进行“人工审核与润色”这也是当前阶段不可或缺的数据独立性测试依赖于“第一个商品”。如果第一个商品缺货或下架了怎么办我们应该让AI使用更稳定的数据比如通过cy.fixture加载一个固定的测试商品ID或者通过API预先创建一个测试商品。我们可以把这个“测试数据准备技能”加入技能库。初始状态测试假设购物车初始为空。我们需要在beforeEach中确保这一点比如调用一个cy.clearCart()的自定义命令这需要后端支持或通过UI操作。断言增强除了徽章数字是否还应该验证购物车页面内的商品列表这取决于需求。我们可以引导AI生成更全面的断言。错误处理可以增加一个用例测试加入失效商品时的错误处理。审核后我们可以将测试改进为// 人工润色后的版本 import { ProductListPage } from ../pages/ProductListPage; import { HeaderComponent } from ../components/HeaderComponent; describe(购物车功能, () { const productListPage new ProductListPage(); const header new HeaderComponent(); let testProductId: string; before(() { // 在全部测试开始前通过API创建一个专用于测试的商品 cy.createTestProduct().then((product) { testProductId product.id; }); }); beforeEach(() { cy.visit(/); // 确保每次测试前购物车是空的 cy.clearTestCart(); // 导航到商品列表页并筛选出我们的测试商品 cy.visit(/products?search${testProductId}); }); after(() { // 测试结束后清理测试商品 cy.deleteTestProduct(testProductId); }); it(将特定测试商品加入购物车后购物车徽章数量应准确更新, () { // 现在可以精确地定位到我们创建的那个测试商品 productListPage.getProductAddToCartButton(testProductId).click(); cy.intercept(POST, **/api/cart/items).as(addToCart); cy.wait(addToCart).its(response.statusCode).should(eq, 200); // 更健壮的断言徽章应显示为“1”且点击购物车图标应跳转到正确页面并包含该商品 header.getCartBadgeCount().should(have.text, 1); // 可选进一步验证购物车详情页 header.goToCart(); cy.url().should(include, /cart); cy.getByTestId(cart-item-${testProductId}).should(be.visible); }); });这个过程体现了“人机协作”的理想模式AI负责生成符合规范、覆盖主要场景的代码草案大幅提升初稿的编写速度人类工程师则负责注入业务上下文、处理边界条件、优化测试数据策略确保测试的稳定性和深度。5. 避坑指南与效能提升将AI引入测试编写流程在带来效率革命的同时也带来了新的挑战。下面是一些从实践中总结的“避坑”经验和进阶技巧。5.1 常见问题与排查问题1AI生成的元素选择器依然脆弱现象AI有时还是会生成像cy.get(‘.btn.btn-primary’)这样的选择器。根因技能库的规则不够强制或者项目前端代码中>## CRUD测试模板 当需要测试创建、读取、更新、删除功能时按以下结构编写 1. **Create**: it(应能成功创建新资源, () { ... })断言创建后列表中存在或跳转到详情页。 2. **Read**: it(应能查看资源详情, () { ... })断言详情页数据与创建时一致。 3. **Update**: it(应能编辑资源, () { ... })修改后保存断言数据已更新。 4. **Delete**: it(应能删除资源, () { ... })删除后断言列表中没有该资源或出现成功提示。 5. **Validation**: it(创建时表单验证应生效, () { ... })测试必填项、格式等。当你说“为‘项目管理’模块生成CRUD测试”时AI会直接套用这个模板生成5个结构化的测试用例框架。技巧2利用AI进行测试重构与维护技能库和AI不仅用于生成新测试更是维护现有测试的利器。当你的前端组件重构>