Skip to content

Too frequent reflows of application (caused by Cypress UI) triggers Error: ResizeObserver loop completed with undelivered notifications #31479

Open
@nsbarsukov

Description

@nsbarsukov

Current behavior

Explore the reproduction section.
The whole application is just this small component:

import {Component} from '@angular/core';

const NOOP = () => {};

@Component({
  standalone: true,
  template: '<input />',
})
export class App {
  constructor() {
    const iframe = document.createElement('iframe');

    document.body.append(iframe);

    const doc = iframe.contentWindow?.document!;
    const observer = new ResizeObserver(NOOP);

    observer.observe(doc.body);
  }
}

It does not produces any errors if your run it in classic environment (just in browser without Cypress).

However it throws the following errors in Cypress UI:

Error: ResizeObserver loop completed with undelivered notifications

According to the spec of the Resize Observer:

Implementations following the specification invoke resize events before paint (that is, before the frame is presented to the user). If there was any resize event, style and layout are re-evaluated — which in turn may trigger more resize events. Infinite loops from cyclic dependencies are addressed by only processing elements deeper in the DOM during each iteration. Resize events that don't meet that condition are deferred to the next paint, and an error event is fired on the Window object, with the well-defined message string:

ResizeObserver loop completed with undelivered notifications.

Desired behavior

As you can see, my reproduction application does not contain anything which could trigger these too frequent reflows.
Most likely Cypress do something.
Probably you should use requestAnimationFrame for your too frequent manipulations with DOM.

See this section: https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver#observation_errors

If you want to prevent these errors, the solution depends on what your intended effect is. If you actually intend to have an infinite loop, you just need to defer the resizing code in your ResizeObserver callback to after the browser repaints. You can put it into a requestAnimationFrame callback.

Test code to reproduce

  1. Create any empty angular project using official Angular CLI. Its content actually does not matter.
    You can use the following command:
ng new cypress-bug-demo --directory=. --style=less --ssr=false
  1. Install Cypress
npm install cypress --save-dev
  1. Enable Angular component testing
npx cypress open

Select "Component testing" and agree with all default configurations (press "Next step"/"Continue" many times).

  1. Create cypress/test.cy.ts file with the following content:
import {Component} from '@angular/core';
import {mount} from 'cypress/angular';

const NOOP = () => {};

@Component({
  standalone: true,
  template: '<input />',
})
export class App {
  constructor() {
    const iframe = document.createElement('iframe');

    document.body.append(iframe);

    const doc = iframe.contentWindow?.document!;
    const observer = new ResizeObserver(NOOP);

    observer.observe(doc.body);
  }
}

describe('Hover any option in the left sidebar of Cypress UI', () => {
  it('It throws Error: ResizeObserver loop completed with undelivered notifications', () => {
    mount(App);
    cy.get('input').type('123');
    cy.get('input').type('456');
  });
});
  1. Run the test in Cypress UI (use Chrome)
  2. Hover any list item of the left sidebar
Image
  1. Cypress throws huge number of the following errors:
(uncaught exception)Error: ResizeObserver loop completed with undelivered notifications.
errors-demo.mov

Cypress Version

14.3.0

Node version

v22.13.1

Operating System

macOS 15.1

Debug Logs

Other

Yep, I know that I can use Cypress.on('uncaught:exception', ...) to filter the following error.
However, it is not an option. The provided implementation is just an oversimplified technical solution for publishable library for many teams (it is not DX-friendly to add this hack to every of hundreds repositories).

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions