Skip to content

add some shadow dom support #7469

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 70 commits into from
Jun 8, 2020

Conversation

43081j
Copy link
Contributor

@43081j 43081j commented May 24, 2020

The shadow dom support issue never seems to go away, and the only PR that tried to do anything about it seems to have gone stale.

So here's some kind of draft of what I had in my head back when the issue was discussed a bit more (#144 ).

Changes

shadow()

Allows you to explicitly traverse into an element's shadow root.

cy
  .get('.foo')
  .shadow()
  .find('.bar')
  .click();

includeShadowDom

Allows you to tell cypress to ignore shadow boundaries, i.e. traverse beyond them.

// finds any .foo in the document and any shadow documents
cy.get('.foo', {includeShadowDom: true});

// finds any .bar in .foo or any shadow documents it contains

cy
  .get('.foo')
  .find('.bar', {includeShadowDom: true});

Keep in mind this means you would not be able to do something like find('.imInOneRoot .imInAnother') because it'd be a nasty idea to have cypress parse that and figure it out.

mouse events

Mouse events are now composed: true by default, just like the browser. This allows clicks on elements inside shadow roots to bubble upwards into the outer document.

isAttached

We now use .isConnected to detect if a given element is attached or not, rather than guessing based on parent traversal.

clicks are deep

Clicks will now click the deepest element at the point you click, not the element in the document where you click.

This basically makes no difference to non-shadow-contained elements.

For shadow contained elements, it means they will be clicked rather than their host.

Example Usage

Given the following DOM

<div class="top-level">
  <my-component>
    #shadow-root
      <button class="my-button">Click me</button>
  </my-component
</div>

You can do:

cy.get('.top-level')
  .find('.my-button', {includeShadowDom: true})
  .click();

// or

cy.get('.top-level > my-component')
  .shadow()
  .find('.my-button')
  .click();

get(selector) behaves differently:

// works, but is probably a bad idea since there could be any number of
// my-button elements in a real app
cy.get('.my-button', {includeShadowDom: true})
  .click();

// DOES NOT WORK
// because it is a cross-boundary selector, i.e. the first part belongs to a different
// component to the second part
cy.get('my-component .my-button', {includeShadowDom: true})
  .click();

This is on purpose, as mentioned earlier. It is better to use get for selecting a particular element, then find within its shadow root.

Keep in mind, it will always be more performant to have direct selectors rather than boundary-ignoring selectors, i.e. the .shadow().find(...) option is always better than using includeShadowDom.

@cypress-bot
Copy link
Contributor

cypress-bot bot commented May 24, 2020

Thanks for the contribution! Below are some guidelines Cypress uses when doing PR reviews.

  • Please write [WIP] in the title of your Pull Request if your PR is not ready for review - someone will review your PR as soon as the [WIP] is removed.
  • Please familiarize yourself with the PR Review Checklist and feel free to make updates on your PR based on these guidelines.

PR Review Checklist

If any of the following requirements can't be met, leave a comment in the review selecting 'Request changes', otherwise 'Approve'.

User Experience

  • The feature/bugfix is self-documenting from within the product.
  • The change provides the end user with a way to fix their problem (no dead ends).

Functionality

  • The code works and performs its intended function with the correct logic.
  • Performance has been factored in (for example, the code cleans up after itself to not cause memory leaks).
  • The code guards against edge cases and invalid input and has tests to cover it.

Maintainability

  • The code is readable (too many nested 'if's are a bad sign).
  • Names used for variables, methods, etc, clearly describe their function.
  • The code is easy to understood and there are relevant comments explaining.
  • New algorithms are documented in the code with link(s) to external docs (flowcharts, w3c, chrome, firefox).
  • There are comments containing link(s) to the addressed issue (in tests and code).

Quality

  • The change does not reimplement code.
  • There's not a module from the ecosystem that should be used instead.
  • There is no redundant or duplicate code.
  • There are no irrelevant comments left in the code.
  • Tests are testing the code’s intended functionality in the best way possible.

Internal

  • The original issue has been tagged with a release in ZenHub.

@CLAassistant
Copy link

CLAassistant commented May 24, 2020

CLA assistant check
All committers have signed the CLA.

@43081j 43081j marked this pull request as draft May 24, 2020 15:11
@43081j 43081j force-pushed the shadows-everywhere branch from 59af811 to a3d34ca Compare May 24, 2020 15:12
@43081j 43081j marked this pull request as ready for review May 27, 2020 08:30
@43081j
Copy link
Contributor Author

43081j commented May 27, 2020

Marking it as ready to review so i can hopefully get some feedback.

It needs catching up from latest dev branch, and there's failing integration tests i haven't managed to track down yet. But the functionality is there and works just fine as far as i've seen.

Yet to add unit tests but this needs reviewing so i don't go down the rabbit hole for no reason.

@43081j 43081j changed the title WIP: add some shadow dom support add some shadow dom support May 27, 2020
@43081j 43081j force-pushed the shadows-everywhere branch from 2a1e1f4 to c74290f Compare May 28, 2020 09:15
@cbowlinger
Copy link

cbowlinger commented May 28, 2020

Hi, I am looking into working with Cypress for some form automation testing and I'm very glad to see people are taking up this task. How would you say progress is going in regards to Cypress' ability in your additions with detecting if elements in the shadow-root are clickable? Or even just progress in general?

I am still relatively new to Cypress, so I am unsure how much help I would be in the review process to move this along in that regard; but you're doing great work that would benefit a lot of people, including myself, and I would love to help where I can.

@43081j
Copy link
Contributor Author

43081j commented May 28, 2020

Really at this point i just need to get the tests passing and have someone from the cypress team review the changes.

I think what could be useful is to hear from people like yourself if the suggested api makes sense:

cy.get('.foo', {ignoreShadowBoundaries: true});
cy.get('.foo').find('.bar', {ignoreShadowBoundaries: true});

I've also changed mouse events to be composed like they are in the browser, I will update my original post with my full list of changes.

@cbowlinger
Copy link

Really at this point i just need to get the tests passing and have someone from the cypress team review the changes.

I think what could be useful is to hear from people like yourself if the suggested api makes sense:

cy.get('.foo', {ignoreShadowBoundaries: true});
cy.get('.foo').find('.bar', {ignoreShadowBoundaries: true});

I've also changed mouse events to be composed like they are in the browser, I will update my original post with my full list of changes.

I think that is the exact API that most of us are looking for, and I think the format for the shadow condition being an optional parameter makes sense with keeping theme of the currently used Cypress API. And if mouse actions are being composed the same way as if they were in the browser, I wouldn't see any issue outside of that.

@cbowlinger
Copy link

Is there a ballpark amount of time you think this will take to be implemented for use? I'm looking at other options for the time being, but I'd love to use Cypress if possible!

@JessicaSachs
Copy link
Contributor

We're reviewing this PR right now and coming up with a more detailed plan, given the awesome work that @43081j has done.

@cbowlinger
Copy link

We're reviewing this PR right now and coming up with a more detailed plan, given the awesome work that @43081j has done.

That's great to hear! From looking through this issue for the last two days, it seems like not being able to see the shadow dom has been one of the only roadblocks for a lot of people in using Cypress. Waiting patiently yet eagerly to hear about this. Great work to @43081j once again!

@JessicaSachs JessicaSachs self-requested a review May 28, 2020 19:57
Copy link
Contributor

@JessicaSachs JessicaSachs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I finished looking through the PR with @chrisbreiding. We'd like to release this behind an experimental feature flag as soon as possible.

Before we can release, we need to:

  1. fix the regressions introduced (I'm starting this now)
  2. add unit tests (I would love @43081j to collaborate on this. He has more context about the code written and the Shadow-DOM specific cases covered)
  3. create an experimental feature flag and add it to the docs (@chrisbreiding or I can do this)
  4. gate the code behind this feature flag

After #1 and #2 are completed, I expect the code will look a bit different. At this point, we'll re-review and clean up the code for nits, etc.

@43081j
Copy link
Contributor Author

43081j commented May 28, 2020

thanks a lot of taking the time to review it.

happy to write the unit tests once i have a dig through the current ones to get my head around it.

i had a lot of trouble getting cypress to build locally (windows, WSL) so haven't been able to easily debug the remaining test failures. i did step through it plenty, which helped me fix most of the failures but these last few are tough. they seem to be something to do with visibility.

im sure like the other tests i figured out, it'll be some minor thing i've missed out in one of my changes.

@JessicaSachs
Copy link
Contributor

@43081j there's a lot of changes in dom/elements.js that we were suspicious of. I haven't started debugging them. I pinged you on twitter if you wanted to collab in realtime and I can help you get your env up.

@43081j
Copy link
Contributor Author

43081j commented May 28, 2020

i added an example shadow() test just to try it out but my local env is failing miserably so i haven't run them. ill do the tests properly tomorrow when i switch machine 👍

@JasonFairchild
Copy link

Will this only work for native shadow DOM? In other words, if the browser being used supports shadow DOM itself, then this will work, but not necessarily with Shadow DOM polyfills or other potentially special implementations of encapsulation/Shadow DOM. I really don't know enough about it to tell from the code, but I know this can be a thing. Figured I'd ask to see if maybe it can help clarify in what cases this may be able to be used.

@43081j
Copy link
Contributor Author

43081j commented May 29, 2020

Shadow dom polyfills/shims will fill in the same API @JasonFairchild , so to cypress it should be transparent as long as your app includes the right polyfill.

@cbowlinger
Copy link

I am thrilled to see the progress made in the last few days on this topic. Is there a relative time frame for when this feature flag could be ready for use? And outside of that, is there anything that people like myself, who are very much interested in using Cypress for future company testing, can do to help with this process?

}

const findShadowRoots = (root: Node): Node[] => {
const doc = root.getRootNode({ composed: true }) as Document
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could use a state method for getting this to use the real document

@JessicaSachs
Copy link
Contributor

@cbowlinger We're not going to commit to a specific date. We just got off the phone with @43081j who plans to bring this in for a landing after adding more tests and some examples in our recipe repository. We plan to help him do that.

Releasing this will coincide with a Cypress binary release date which happens every two weeks.

@43081j 43081j force-pushed the shadows-everywhere branch from 3be576e to 4a262fe Compare May 31, 2020 16:35
@JessicaSachs
Copy link
Contributor

JessicaSachs commented Jun 5, 2020

Happy Friday!

We have a PR for the docs open here. We don't usually provide detailed docs for experimental features, but the types and recipes will help you.

We are waiting to choose a flag name using active voice (e.g. instead of ignoreShadowBoundaries we use searchShadow or traverseShadowBoundaries etc)

We'll update all the references of ignoreShadowBoundaries in this PR to use the new name and then after a quick internal demo of the example recipes (cypress-io/cypress-example-recipes#501) we should be able to merge.

Copy link
Contributor

@JessicaSachs JessicaSachs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

YES

@chrisbreiding chrisbreiding merged commit a7ff8fd into cypress-io:develop Jun 8, 2020
@43081j 43081j deleted the shadows-everywhere branch June 8, 2020 19:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add support for shadow dom
7 participants