You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何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');

关键优化点

  1. 区分嵌套属性与Cypress方法:优先返回预定义的嵌套选择器属性,避免误触发cy.get
  2. 避免内部属性触发cy.get:方案一通过缓存Chainable实例转发所有属性访问;方案二仅处理用户方法,内部属性由实际Chainable实例处理
  3. 保持简洁调用语法:两种方案都无需额外添加.get即可实现你期望的链式调用

内容的提问来源于stack exchange,提问作者user3534080

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 07:50:59