Giter Club home page Giter Club logo

cypress-shadow-dom's Introduction

(deprecated) cypress-shadow-dom

GitHub license npm version All Contributors

Extend Cypress commands with shadow DOM support

This package adds a custom Cypress command that allows you to make an abstraction on how exactly you upload files through you HTML controls and focus on testing the functionality.

Project reached its dead end because of recent feature introduced by @43081j (and reference issue cypress/issues/144).

Please consider using this experimental built-in feature as well as submitting issues and code contributions there.

Warmest thanks for all the contributors that helped this project evolve!

Table of Contents

Installation

The package is distributed via npm should be installed as one of your project's devDependencies:

npm install --save-dev cypress-shadow-dom

Usage

cypress-shadow-dom extends Cypress' cy command. Add this line to your project's cypress/support/commands.js:

import 'cypress-shadow-dom';

Here is a basic example:

cy.shadowGet('todo-list')
  .shadowFind('todo-list-item')
  .its('length')
  .should('eq', 4);

See more usage guidelines in example. It also contains all the available commands in their natural use case.

API

Here's a set of available commands:

shadowGet

Querying shadow DOM elements is made with:

cy.shadowGet(selector, options);
  • {String} selector – a single selector which usually represents root shadow DOM elements you want to start with

  • {Object?} options – (optional) contains following properties:

    • {Number?} timeout – (optional) time, in milliseconds, to wait until most DOM based commands are considered timed out (defaults to 4000)

This command returns shadowSubject that is a valid subject to execute any command below.

shadowFind

Additional querying within found shadow DOM elements:

shadowSubject.shadowFind(selector, options);
  • {String} selector – a single selector which helps to get nested shadow DOM element under the root element

  • {Object?} options – (optional) contains following properties:

    • {Number?} timeout – (optional) time, in milliseconds, to wait until most DOM based commands are considered timed out (defaults to 4000)

Example:

cy.shadowGet('todo-list').shadowFind('todo-form');

This command returns shadowSubject that is a valid subject to execute any command below.

In order to set a custom timeout for dynamically loaded elements that appear later than 4 seconds after render, use custom timeout:

cy.shadowGet('todo-list').shadowFind('todo-form', { timeout: 8500 });

shadowEq

To take the nth element from found shadow DOM collection:

shadowSubject.shadowEq(index, options);
  • {Number} index – a positive or negative number within given collection range

  • {Object?} options – (optional) contains following properties:

    • {Number?} timeout – (optional) time, in milliseconds, to wait until most DOM based commands are considered timed out (defaults to 4000)

shadowFirst

To take the first element from found shadow DOM collection:

shadowSubject.shadowFirst(options);
  • {Object?} options – (optional) contains following properties:

    • {Number?} timeout – (optional) time, in milliseconds, to wait until most DOM based commands are considered timed out (defaults to 4000)

So, simply:

cy.shadowGet('todo-list')
  .shadowFind('todo-form')
  .shadowFirst();

shadowLast

To take the last element from found shadow DOM collection:

shadowSubject.shadowLast(options);
  • {Object?} options – (optional) contains following properties:

    • {Number?} timeout – (optional) time, in milliseconds, to wait until most DOM based commands are considered timed out (defaults to 4000)

shadowContains

To validate some element's text content:

shadowSubject.shadowContains(content, options);
  • {String} content – a string containing any text for lookup

  • {Object?} options – (optional) contains following properties:

    • {Number?} timeout – (optional) time, in milliseconds, to wait until most DOM based commands are considered timed out (defaults to 4000)

shadowTrigger

To trigger any event:

shadowSubject.shadowTrigger(eventName, options);
  • {String} eventName – a string containing any text for lookup

  • {Object?} options – (optional) contains following properties:

    • {Boolean?} force
    • {Boolean?} bubbles
    • {Boolean?} cancelable
    • {Boolean?} composed

shadowClick

A shorthand to trigger a click event:

shadowSubject.shadowClick(options);
  • {Object?} options – (optional) contains following properties:

    • {Boolean?} force
    • {Boolean?} bubbles
    • {Boolean?} cancelable
    • {Boolean?} composed

shadowType

Types some text content inside given shadow DOM input control:

shadowSubject.shadowType(content, options);
  • {String} content – a string containing any text

  • {Object?} options – (optional) contains following properties:

    • {Number?} delay – (optional) time, in milliseconds, between adding each letter/char (defaults to 10)

Contributors

Thanks goes to these wonderful people (emoji key):


tst

🐛

Joshua de Lange

🐛

Lucas Schnüriger

💻

Milan Andric

📖 🤔

Ryan Wheale

🤔 💻

This project follows the all-contributors specification. Contributions of any kind welcome!

License

MIT

cypress-shadow-dom's People

Contributors

abramenal avatar allcontributors[bot] avatar culas avatar designbyonyx avatar greg-at-spark avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

cypress-shadow-dom's Issues

[Bug] - cannot find items in light dom of host elements

Current behavior:

First, thanks so much for the work on this.

I am using StencilJS and Ionic to build a component library, and I'm working with a simple component with a structure like this where everything insidestls-custom-component is within a shadow dom and the ion-item renders slotted content within its own shadow dom. I am unable to select an ion-button from the context of its parent ion-item.

<stls-custom-component>
    # shadowRoot
        <ion-item class="foo">
            <ion-button>Foo</ion-button>
        </ion-item>
        <ion-item class="bar">
            <ion-button>Bar</ion-button>
        </ion-item>
</stls-custom-component>

I am using the following commands:

cy.shadowGet('stls-custom-component')
  .shadowFind('ion-item.foo')
  .shadowFind('ion-button')
  .shadowClick();

Desired behavior:

The problem is that the shadowFind('ion-button') is only searching in the shadowRoot on the ion-item, but the ion-button is in the light dom. To best describe the request I am making, consider the following elGetter:

const elGetter = () => {
    // search the light dom first
    let found = subject[0].querySelectorAll(selector);

    // if nothing is found, and the element is a host element, search the shadow dom
    if(!found && subject[0].shadowRoot) {
        found = subject[0].shadowRoot.querySelectorAll(selector);
    }

    return found;
};

Steps to reproduce: (app code and test code)

I am glad to provide a repo if the above is insufficient - just let me know.

Versions

[email protected]
[email protected]

[Bug] shadowTrigger fails with options parameter

Maybe I am using the API incorrectly? I know this example might not be the best one, but was curious why this test fails?

diff --git a/example/cypress/integration/todolist.spec.js b/example/cypress/integration/todolist.spec.js
index fd89ff7..d189c9b 100644
--- a/example/cypress/integration/todolist.spec.js
+++ b/example/cypress/integration/todolist.spec.js
@@ -66,4 +66,10 @@ describe('Todo List', () => {
       .shadowFind('label')
       .shadowContains('async item');
   });
+
+  it('trigger allows options parameter', () => {
+    cy.shadowGet('todo-list-item', { timeout: 6000 })
+      .shadowFind('input')
+      .shadowTrigger('click', { timeout: 1000 });
+  });
 });

Screen Shot 2019-11-25 at 1 05 56 PM

[Bug] - shadowClick is not working for me

First sorry for my bad englis, I am automating a web page but I have some problems with shadow root, so let's see them

Current behavior:

This is input user
user

This is input pass
pass

and finally the button
btn

Desired behavior:

Steps to reproduce: (app code and test code)

import 'cypress-shadow-dom';
///
describe('Mi Primera Prueba', function () {

it('Prueba Shadow Dom', function () {
    cy.visit('url')
    cy.shadowGet(':nth-child(2) > :nth-child(1) > .ng-untouched').shadowType("B26192");
    cy.shadowGet('.mt-1 > .ng-untouched').shadowType("Interbank2");
    cy.shadowGet('.mt-3 > .col-xs-12').shadowClick();
})

})

but this is the result, I don't know why he doesn't click on the button
result

P lease tell me what I'm doing wrong =( !!! Thank u very much

Versions

Cypress verson: 3.8.1
cypress-shadow-dom: 1.3.0

[Bug]

Current behavior:

  1. e2e tests for MP lookup finds the mp lookup embed:
    CypressError: Timed out retrying: Expected to find element: 'undefined', but never found it.

Desired behavior:

Tests pass

Steps to reproduce: (app code and test code)

spec.js ->
import 'cypress-shadow-dom';
describe('e2e tests for MP lookup', () => {
  it('finds the mp lookup embed', () => {
  	cy.visit('https://www.bbc.co.uk/news/uk-politics-49571868');
  	cy.get('.bbc-news-vj-embed-wrapper')
  	cy.wait(500);

  	cy.shadowGet('.bbc-news-vj-wrapper')
  	  .shadowFind('.gel-wrap');

  	cy.shadowGet('.mps-lookup')
  	  .shadowFind('.lookup-header').wait(5000);

  });
 
})
commands.js
import 'cypress-shadow-dom';
index.js
import './commands';
I have created a branch locally, however do not have the right permissions to push to `cypress-io/cypress-test-tiny.git`

Versions

"cypress": "^3.6.1",
"cypress-shadow-dom": "^1.1.1"
Mac OS 10.12.6 , Running tests off Terminal Version 2.7.5 npx cypress run or npx cypress open

[Bug] Chaining .should throws an error.

Current behavior:

Hey guys,

As soon as I chain .should to the end of a shadowGet, the following error is thrown:

CypressError: Timed out retrying: cy.should() failed because this element is detached from the DOM.

<div id="jl-myaccount-components--sidebar">...</div>

Cypress requires elements be attached in the DOM to interact with them.

The previous command that ran was:

  > cy.shadowGet()

    This DOM element likely became detached somewhere between the previous and current 
    command.

   Common situations why this happens:
      - Your JS framework re-rendered asynchronously
      - Your app code reacted to an event firing and removed the element

    You typically need to re-query for the element or add 'guards' which delay Cypress from running 
    new commands.

    https://on.cypress.io/element-has-detached-from-dom

I noticed in the examples that .should is mentioned, just wondering why it's not working for me?

Having a test that simply does a shadowGet with a shadowFind chained off it doesn't sit too well
with me, so I'd like to know how I can assert something in the shadow dom.

Desired behavior:

.should chaining should work.

Steps to reproduce: (app code and test code)

The following piece of code throws the error:

cy.shadowGet('x-jl-mya-sidebar')
.shadowFind('div#jl-myaccount-components--sidebar').should('be.visible')

Versions

Cypress 4.0.1 and latest version of cypress-shadow-dom.

[Bug] Not able to locate the shadow element

Current behavior:

I don't seem to be able to locate the elements inside
Cypress keeps throwing the following error
[cypress-shadow-dom error]: Error: element not found.
Check provided lookup conditions

the root element gets located, however the ShadowFind() fails when trying to locate the child node in the shadow DOM

not found.

logError @ cypress_runner.js:157775
(anonymous) @ cypress_runner.js:157448
emit @ cypress_runner.js:121451
(anonymous) @ cypress_runner.js:101926
emit @ cypress_runner.js:121451
emit @ cypress_runner.js:101958
_onErrorClick @ cypress_runner.js:100849
(anonymous) @ cypress_runner.js:102077
executeAction @ cypress_runner.js:141107
res @ cypress_runner.js:141098
ca @ cypress_runner.js:149113
ja @ cypress_runner.js:149114
ka @ cypress_runner.js:149114
wa @ cypress_runner.js:149116
Aa @ cypress_runner.js:149117
ya @ cypress_runner.js:149117
Da @ cypress_runner.js:149120
Ad @ cypress_runner.js:149183
Gi @ cypress_runner.js:149349
Kb @ cypress_runner.js:149138
Dd @ cypress_runner.js:149185
(anonymous) @ cypress_runner.js:149350
./node_modules/scheduler/cjs/scheduler.production.min.js.exports.unstable_runWithPriority @ cypress_runner.js:152175
Ii @ cypress_runner.js:149350
Cd @ cypress_runner.js:149184

Desired behavior:

I should be able to locate the elements within the shadow dom using this extended feature

when writing the test scenario using the following DOM extended method
like the following:

Steps to reproduce: (app code and test code)

cy.visit('/pagename')
cy.shadowGet('login-page')
.shadowFind('.login-button')
.shadowTrigger('click')

Versions

"cypress": "^3.3.1",
"cypress-shadow-dom": "^1.0.0",

Macbook Pro

shadowEq method enhancement

Current behavior:

shadowEq returns the nth element from found shadow DOM collection

Desired behavior:

Could we please have option to pass text in shadoweq method so it will return the element having that text from collection? We are using this method to select data from dropdown, If some value is added or deleted from dropdown collection, test fails as it is unable to find that option in that position. If we can select value of dropdown by passing text, it will always find tat option and addition/deletion dropdown data will not cause test failure.

Versions

Cypress 4.x.x support?

Versions Support

Will current Cypress-Shadow-Dom version 1.3.0 support Cypress 4.x.x?

Thanks

[Feature] cy.shadowFind doesn't repeat until a timeout

It seems that cy.shadowFind doesn't work like cy.get because after a click I must use cy.wait(500) and then make a find. It seems that cy.shadowFind doesn't repeat more times until a timeout... Is it true? I'm a newbie with Cypress and I'm not so sure...

This is my code:

it('test first table', () => {
  cy.visit('http://localhost:4000/#/dataTable/basic');

  cy.shadowGet('kup-data-table')
    .shadowFind('.density-medium')
    .its('length')
    .should('eq', 1);

  cy.shadowGet('kup-data-table')
    .shadowFind('kup-button')
    .shadowFind('button')
    .shadowTrigger('click');

  // cy.shadowFind don't seem to be repeated until a timeout like cy.get...  -> actually used a manual wait!
  cy.wait(500);

  cy.shadowGet('kup-data-table')
    .shadowFind('.density-small')
    .its('length')
    .should('eq', 1);
});

Can you help me?
If it is how I think the library can be improved adding a timeout?
If I'm wrong could you tell me how to avoid using cy.wait?

Thanks a lot!

[Feature] .shadowContains should accept RegEx

Current behavior:

They cypress command also accepts regular expressions

contains(/^foobar$/)

Desired behavior:

The shadowContains command should also accept regular expressions.

[Feature] - add support for aliasing

Current behavior:

There is currently no way to share objects between tests. This results in a lot of get/find operations for every test as each test needs to repeatedly pierce into the same shadow structures before making any assertions.

Desired behavior:

Enable the as('alias') or shadowAs('alias') command to work and allow shadowGet('@alias') to retrieve these values. This should use mocha's "context". Note: there's a possibility that the default "as" command already works and we just need to update shadowGet.

beforeEach(() => {
  cy.shadowGet('todo-list')
    .shadowFind('todo-item')
    .as('todoItem');
});

it('does the thing', () => {
  cy.shadowGet('@todoItem').shadowContains('do the laundry');
});

[Feature] Allow the retrieval of regular DOM elements from nodes that contain a Shadow DOM

Current behavior:

I have something Similar to this

<my-component>
  #shadowRoot
    <irregular-component>
      #shadowRoot 
        <span>this is inside the shadow root</span>
      <span id="desired-element">this is outside the shadow root</span>
    </irregular-component>
</my-component>

I have tried to access the span with id="desired-element", however I have been unsuccessful.
I have used the following commands and they give me errors:

cy.shadowGet('my-component').shadowFind("irregular-component").shadowFind('#desired-component')
cy.shadowGet('my-component').shadowFind("irregular-component > #desired-component")
cy.shadowGet('my-component').shadowFind("irregular-component #desired-component")

Desired behavior:

It would be nice to be able to retrieve regular DOM nodes inside a shadowRoot element within a component that has a shadowRoot.

This is a niche situation, however I am struggling to figure out how to do this. If I am missing something, or there is a way to achieve this without a new feature, I'd love to know how to do it! Thanks for reading :)

all modules installed with yarn
cypress: ^4.8.0
cypress-shadow-dom: ^1.4.0
OS: ubuntu 16.04 LTS 64-bit

shadowFind works with cypress runner but doesn't work when run in the command line

I'm using shadowFind in a test:
cy.shadowGet('.ui-widget')
.shadowFind('.logo-wrapper')
.shadowContains('logoText')
It works fine when using the cypress runner but when I try 'cypress run' to run it in the command line it doesn't work:
CypressError: Timed out retrying: Expected to find element: 'undefined', but never found it.

Am I doing something incorrectly?

Thanks!

[Feature] - shadowType accept special characters

Current behavior:

shadowType split every character in the text and creates a keyboardEvent for each of them.

Desired behavior:

Like cy.type, shadowType could have the option to allow special characters like "ESC" or "backspace" and create a keyboardEvent for the corresponding special character.

[Feature] Add support to mimic cy.check and cy.select

Current behavior:

Unable to use .check and .select.

Desired behavior:

Would like support for cy.check and cy.select. Currently trying to use shadow.click however that doesnt seem to work.

Versions

Chrome on Mac and Windows

[Bug] Can't use "type" command within shadow DOM

Current behavior:

Screenshot 2019-06-21 13 51 28

Desired behavior:

It should work

Steps to reproduce: (app code and test code)

Screenshot 2019-06-21 13 51 11
Screenshot 2019-06-21 13 50 52
Screenshot 2019-06-21 13 50 41

***We have an iframe that contain shadow dom. And we want to get element inside that iframe to handle, but not working at current.

Versions

cypress: 3.3.1

[Feature] Add shadowNth command

Current behavior:

Selection of first and last elements is available now, but it would be nice to have more flexibility with providing just index of needed element

[Bug] shadowFind doesn't work with using a space in an attribute selector

Thank you for the great plugin!

Current behavior:

I want to find a shadow element where its placeholder attributer is "First Name", but it's failing with the error:

[cypress-shadow-dom error]: Selector must be single.
In case if you need multiple please chain it with .shadowFind() command

Screenshot 2019-10-10 at 14 35 18

Desired behavior:

The element to be found.

Steps to reproduce: (app code and test code)

Have a shadow element with a placeholder attribute with a space in its value.

Then trying to find it it with;
cy.shadowGet('lightning-input').shadowFind('input[placeholder="First Name"]').shadowType('123123123')

Versions

Cypress 3.4.1, macOS 10.14.5, Chrome 77.0.3865.90

Thank you!

[Bug] TypeError: Cannot read property 'shadowRoot' of undefined

Current behavior:

I am using shadowGet to find and match the contents of an ion-toast. If I use something like:

cy.shadowGet('ion-toast')
    .shadowFind('div.toast-message')
    .shadowContains('Success');

it fails with TypeError: Cannot read property 'shadowRoot' of undefined.

However, if I insert a .wait(200) right after the shadowGet, it works. It seems that the shadowFind does not wait for the element to be accessible or something.

Desired behavior:

It should work without the wait workaround.

Versions

Cypress 3.7.0
cypress-shadow-dom 1.2.0
Ionic 4.11.4
Angular 8.1.3
Ubuntu 19.10
Chrome 78

[Bug] Implementing cypress-shadow-dom as typescript

Description

we're implementing cypress-shadow-dom in our project, but we also use Cypress with Typescript. We tried to add the package with the following statement, but it didn't work:

/// <reference path="../node_modules/cypress-shadow-dom/index.d.ts" />

Could you please advise us on how to implement it?

Cypress shadow dom Not working headless

Current behavior:

It is working fine if we execute test cases in chrome browser.

Desired behavior:

Same test cases which are working fine in browser is not working in headless mode.
cypress run --headless --browser chrome

Test cases are failing where we are trying to find shadow dom element using this plug in.

Versions

[Bug] shadowContains does not retry if the item is not found

Current behavior:

Using shadowContains suffers from most of the same issues as shadowFind (#25 and fixed in #26). The biggest issues is that it does not retry if the element is not immediately found. It also doesn't search the light DOM of custom elements. After researching the internals, Cypress only triggers its "retry" logic if a method returns a jquery collection. Using Cypress.$ to query the DOM fixes the issue. I plan on submitting a PR soon.

Desired behavior:

If the element is not found immediately, Cypress should retry until the timeout is reached.

Steps to reproduce: (app code and test code)

Try to use shadowContains on an element which is not immediately available. I can create a repo if need be - just let me know.

Versions

[email protected]
[email protected]

[Feature] - override $.contains to work with shadow trees

Current behavior:

There are still code paths which trigger Cypress' internal "ensureAttached" and friends which detects whether a DOM element is still attached to the DOM. For example, the following fails because Cypress thinks the input is detached:

cy.shadowGet('some-element')
  .shadowFind('input[type="checkbox"]')
  .shadowClick()
  .should('be.checked'); // error - input is detached from dom

Desired Behavior

Instead of reimplementing a shadow-friendly method across the entire Cypress API (especially should), we can extend the underlying utility methods to work with shadow trees. In this case, all code paths eventually call $.contains(doc, el) to determine whether or not the element is attached to the DOM. We can override the $.contains method to make it work with shadow structures by crawling up every "rootNode" until we reach the document.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.