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

自定义Chai断言运行时Cypress陷入循环问题求助

Fixing Infinite Loops in Custom Cypress Chai Assertions

Looks like you’re hitting a common snag when mixing Cypress’s asynchronous command flow with Chai’s assertion system. The infinite WRAP/GET loops happen because your custom assertion isn’t properly handling async operations, causing Cypress to retry the assertion indefinitely. Let’s break down the fixes and get your code working:

Key Issues in Your Code

  1. Broken promise chain: Your getRects function doesn’t return the inner promise, so it resolves to undefined instead of the rect data your assertion needs.
  2. Misaligned async/sync logic: Chai assertions are designed to be synchronous, but you’re calling asynchronous Cypress commands directly inside the assertion method. This triggers Cypress’s retry mechanism non-stop because it can’t resolve the pending commands.

Fixed Implementation

Updated Support File (cypress/support/index.js)

function getRect(subject) {
  // Handle Cypress jQuery objects (what `this._obj` will be)
  if (Cypress.$.isJQuery(subject)) {
    return cy.wrap(subject).then($elem => $elem[0].getBoundingClientRect());
  }
  // Handle document reference
  if (subject === '&document') {
    return cy.document().then(doc => doc.documentElement.getBoundingClientRect());
  }
  // Handle selector strings
  if (typeof subject === 'string') {
    return cy.get(subject).then($elem => $elem[0].getBoundingClientRect());
  }
  // Handle raw DOM elements
  return cy.wrap(subject).then(elem => elem.getBoundingClientRect());
}

function getRects(first, second) {
  // Return the full promise chain so rect data propagates correctly
  return getRect(first).then(actualRect => {
    return getRect(second).then(expectedRect => [actualRect, expectedRect]);
  });
}

const aligned = (_chai, utils) => {
  _chai.Assertion.addMethod('leftAligned', function(expectedSelector) {
    const actualSubject = this._obj; // This is the Cypress jQuery object from cy.get()
    
    // Return a promise to let Chai wait for async rect data
    return getRects(actualSubject, expectedSelector).then(([actual, expected]) => {
      this.assert(
        actual.left === expected.left,
        `Expected #{this} to be left-aligned with ${expectedSelector}`,
        `Expected #{this} to NOT be left-aligned with ${expectedSelector}`,
        expectedSelector
      );
    });
  });
};

chai.use(aligned);

Test File (cypress/integration/test.js)

Your test code stays exactly the same—no changes needed here:

describe('testing custom chai', () => {
  it('uses a custom chai helper', () => {
    cy.visit('https://www.bbc.co.uk/news');
    cy.get('#orb-modules > header').should('be.leftAligned', '#orb-header');
  });
});

What Changed?

  • Fixed promise propagation: getRects now returns the full promise chain, ensuring your assertion receives the actual rect values instead of undefined.
  • Proper subject handling: The getRect function now correctly identifies and processes Cypress jQuery objects (which is what this._obj refers to in the assertion), eliminating unnecessary cy.wrap calls that caused loops.
  • Async-aware assertion: By returning the promise from getRects, we let Chai wait for the async rect data to load before running the assertion. This plays nicely with Cypress’s retry mechanism, as it can now detect when the async operation completes.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 06:58:01