为何Proxy会被嵌套元素调用?Cypress封装异常排查
优化Cypress Proxy实现方案
针对你遇到的Proxy触发未使用属性导致重复调用cy.get的问题,以下提供两种优化方案,可根据需求选择:
方案一:缓存Chainable实例(单次cy.get复用)
该方案会在首次访问任何属性时创建cy.get的Chainable实例并缓存,后续所有属性访问都复用此实例,彻底避免重复调用cy.get。适合不需要每次方法调用都刷新DOM查询的场景。
const CACHED_CHAINABLE = Symbol('cachedChainable'); function proxifiedGet(selector: string) { return new Proxy({}, { get(target, property) { // 优先返回嵌套的选择器属性(如todoPage、main等) if (property in target) { return target[property as keyof typeof target]; } // 初始化并缓存Chainable实例 if (!target[CACHED_CHAINABLE]) { target[CACHED_CHAINABLE] = cy.get(selector); } // 将所有属性访问转发到缓存的Chainable return target[CACHED_CHAINABLE][property as keyof typeof target[CACHED_CHAINABLE]]; } }); } // 嵌套属性定义示例(实际项目可通过算法自动生成) const todoApp = proxifiedGet('[data-test=todo_app]'); Object.defineProperties(todoApp, { todoPage: { value: proxifiedGet('[data-test=todo_app] [data-test=todo_page]') }, main: { value: proxifiedGet('[data-test=todo_app] [data-test=todo_page] [data-test=main]') }, rows: { value: proxifiedGet('[data-test=todo_app] [data-test=todo_page] [data-test=main] [data-test=rows]') }, row: { value: proxifiedGet('[data-test=todo_app] [data-test=todo_page] [data-test=main] [data-test=rows] [data-test=row]') } }); // 简洁调用(复用同一个cy.get结果) todoApp.row.first().should('have.text', 'Pay electric bill'); todoApp.row.last().should('have.text', 'Walk the dog');
方案二:方法包装器(每次方法调用触发新cy.get)
该方案只为用户常用的Cypress方法创建包装函数,仅在方法调用时才执行cy.get,完全匹配你期望的等价代码逻辑。内部属性会被转发到方法返回的Chainable实例,不会触发额外的cy.get。
function proxifiedGet(selector: string) { return new Proxy({}, { get(target, property) { const propertyStr = property.toString(); // 仅处理用户会调用的Cypress方法(可根据需求扩展) const cypressMethods = ['first', 'last', 'within', 'should', 'and', 'click', 'type']; // 为Cypress方法返回包装函数,调用时触发新的cy.get if (cypressMethods.includes(propertyStr)) { return (...args: any[]) => { return cy.get(selector)[propertyStr](...args); }; } // 返回嵌套的选择器属性 if (property in target) { return target[property as keyof typeof target]; } // 其他属性返回undefined(不影响Cypress内部逻辑) return undefined; } }); } // 嵌套属性定义与方案一一致 // ... // 简洁调用(每次方法调用都是独立的cy.get) todoApp.row.first().should('have.text', 'Pay electric bill'); todoApp.row.last().should('have.text', 'Walk the dog');
关键优化点
- 区分嵌套属性与Cypress方法:优先返回预定义的嵌套选择器属性,避免误触发
cy.get - 避免内部属性触发
cy.get:方案一通过缓存Chainable实例转发所有属性访问;方案二仅处理用户方法,内部属性由实际Chainable实例处理 - 保持简洁调用语法:两种方案都无需额外添加
.get即可实现你期望的链式调用
内容的提问来源于stack exchange,提问作者user3534080
相关产品推荐
相关产品推荐

