cypress-io / cypress

Fast, easy and reliable testing for anything that runs in a browser.
https://cypress.io
MIT License
46.59k stars 3.15k forks source link

Angular component tests mounts fail for ViewEncapsulation ShadowDom #26673

Open Legiew opened 1 year ago

Legiew commented 1 year ago

Current behavior

If you create a component tests for an angular component the mounting steps execute without an error. If you switch the ViewEncapsulation for this component to ShadowDom only the first mount executes without an error. All other mount calls result in the error "NottSupportedError: Failed to execute 'attachShadow' on 'Element': Shadow root cannot be created on a host which already hosts a shadow tree." The order of the tests is important not the tests themselfs. If you switch the order of the tests again the first one runs through and all others fail.

Desired behavior

Component testing with angular and ViewEncapsulation ShadowDom should mount everytime without a problem.

Test code to reproduce

Minimal repo created with Angular CLI 15, latest cypress version and failing component tests: https://github.com/Legiew/cy-component-shadow-dom npm run cypress:open > execute component tests for app.component

Cypress Version

12.11.0

Node version

18.16.0

Operating System

Windows 11

Debug Logs

No response

Other

No response

warrensplayer commented 1 year ago

@Legiew , I have replicated your problem in the latest version of Cypress and will forward this ticket to the appropriate team. They will soon evaluate the priority of this ticket and consider their capacity to pick it up. Please note that this does not guarantee that this issue will be resolved. The ticket will indicate status changes during evaluation, so we ask that you please refrain from asking for updates. Thanks!

jtuds commented 1 month ago

@Legiew Did you find a workaround for this? Experiencing the same issue when rendering a standalone component that uses ShadowDom ViewEncapsulation

jclark86613 commented 1 month ago

I to would be keen or a fix or workaround. Otherwise using Cypress is an unattainable position for my product.

jclark86613 commented 1 month ago

@jtuds @Legiew @warrensplayer I have a tentative workaround at the moment.

The root of the problem appears to be Cypress tries to redefine a shadowRoot, on a DOM Element that already has a shadowRoot attached to. As per the HTML spec, you cannot do this and you cannot remove a shadowRoot on an element that already has one.

What I have done, is in the beforeEach block, I call a utility function I have created. This utility function removes the element with the property data-cy-root and replace it with a new dom element <div data-cy-root></div>.

// find an element with attribute  `data-cy-root`
const el = document.querySelector('[data-cy-root]');
// if the el has a shadow root them remove it
if (el?.shadowRoot) {
    el.remove();
    // create <div data-cy-root></div> and attach to body
    const div = document.createElement('div');
    div.setAttribute('data-cy-root', '');
    document.body.appendChild(div);
}

This mimics the initial DOM state of the runner before the first test is mounted and ran. However, I am not sure of the robustness of this workaround as I am not sure if there is any other cleanup that is required to unmount.

I suspect this should be fine, as Cypress appears to be doing the rest of its cleanup as expected, it just needs a defensive check to ensure it doesn't run Element.attachShadow() on a element that already has a shadow root.

jclark86613 commented 1 month ago

Just to share more information, before I found this issue ticket, I raised the question on stack overflow and got an answer very similar to my above workaround, in case people need other workarounds:

https://stackoverflow.com/a/78723531/4768251