-
Notifications
You must be signed in to change notification settings - Fork 676
Gh2172 Add ShadowRoot()
as a chainable Selector method
#5560
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
Conversation
❌ Tests for the commit 28d84e4 have failed. See details: |
@mostlyfabulous import { Selector } from 'testcafe';
fixture `Selector`
.page `../pages/index.html`;
test('shadowRoot selector API tests', async t => {
await t.click(Selector('#hasShadowDOM').shadowRoot().child('p').withText('Text should be found!'));
}); I debugged your code and found a couple of issues to fix. We would appreciate it if you review the recommendations from the following comment: #2172 (comment) |
❌ Tests for the commit 0e9e4cf have failed. See details: |
✅ Tests for the commit 7272508 have passed. See details: |
❌ Tests for the commit 3900fe5 have failed. See details: |
❌ Tests for the commit f2d84de have failed. See details: |
@mostlyfabulous
Then, remove all IE related code in your test as follows: const isIEFunction = ClientFunction(() => { In addition, there is no need to create/copy tests for all selector properties. A test with one property is enough. |
Do you mean to say, wrap any code specific to IE in the function you provided? |
❌ Tests for the commit c36f8bb have failed. See details: |
c36f8bb
to
6c161aa
Compare
❌ Tests for the commit 6c161aa have failed. See details: |
No. I saw this function in your code. Probably you accidentally copied it from another test file. I mean, that we do not need any additional code for IE, since IE does not support shadow DOM. |
@testcafe-build-bot restart |
@mostlyfabulous Please also rebase your commit to the DevExpress/master branch since some npm packages need to be refreshed. |
@mostlyfabulous |
I should be able to get round to the changes you suggested this week but feel free to finish the outstanding changes so this can be released! |
Ok, |
❌ Tests for the commit 0a0c260 have failed. See details: |
@testcafe-build-bot retest |
✅ Tests for the commit 0a0c260 have passed. See details: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
An excellent PR, thank you. Just some moments to discuss :)
// NOTE: we can search for elements only in document or element. | ||
if (querySelectorRoot.nodeType !== 1 && querySelectorRoot.nodeType !== 9) | ||
// NOTE: we can search for elements only in document/element/shadow root. | ||
if (querySelectorRoot.nodeType !== 1 && querySelectorRoot.nodeType !== 9 && querySelectorRoot.toString() !== '[object ShadowRoot]') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess we can check here for nodeType === 11
(document fragments' node type) since shadow roots have this node type and document fragments have the querySelectorAll
methods:
https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was my initial approach, but then I saw the hammerhead implementation =)
@@ -762,6 +762,28 @@ function addHierarchicalSelectors (options) { | |||
|
|||
return createDerivativeSelectorWithFilter(args); | |||
}; | |||
|
|||
// ShadowRoot | |||
obj.shadowRoot = (filter, dependencies) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
filter
can be used when a method can produce multiple results from a single element (e.g. the parent
method that matches all parent nodes from the current element up to the document element). dependencies
can be used when filter
is a function or a ClientFunction
to pass some context variables. Since an element can have only a single shadowRoot
, I think we do not need filter
and dependencies
here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agree
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense to me now
@@ -63,6 +64,9 @@ export default class SelectorExecutor extends ClientFunctionExecutor { | |||
const isElementVisible = !this.command.visibilityCheck || visible(el); | |||
const isTimeout = new DateCtor() - startTime >= this.timeout; | |||
|
|||
if (domUtils.isShadowRoot(el)) | |||
throw new ActionElementIsShadowRootElementError(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't feel that here is the right place for this check. By doing it here, we prevent using expressions like t.expect(element.shadowRoot()).contains('text')
that are perfectly valid in my opinion. I think it's better to do it here:
https://github.com/DevExpress/testcafe/blob/master/src/client/driver/command-executors/execute-action.js#L157
❌ Tests for the commit db511da have failed. See details: |
@testcafe-build-bot retest |
1 similar comment
@testcafe-build-bot retest |
✅ Tests for the commit db511da have passed. See details: |
@AndreyBelym FPR |
ShadowRoot()
as a chainable Selector method
[AlexanderMoiseev](https://github.com/AlexanderMoiseev) [augustomezencio-hotmart](https://github.com/augustomezencio-hotmart) - [Fix tree-kill vulnerability from old version.](#5690) [bdwain](https://github.com/bdwain) - [Fixes header types for request and response mocks (#5529)](#5530) [mostlyfabulous](https://github.com/mostlyfabulous) - [Gh2172 Add `ShadowRoot()` as a chainable Selector method](#5560) [danielroe](https://github.com/danielroe) - [Use polyfill if `location.origin` doesn't exist (in IE11)](DevExpress/testcafe-hammerhead#2441)
[AlexanderMoiseev](https://github.com/AlexanderMoiseev) [augustomezencio-hotmart](https://github.com/augustomezencio-hotmart) - [Fix tree-kill vulnerability from old version.](DevExpress#5690) [bdwain](https://github.com/bdwain) - [Fixes header types for request and response mocks (DevExpress#5529)](DevExpress#5530) [mostlyfabulous](https://github.com/mostlyfabulous) - [Gh2172 Add `ShadowRoot()` as a chainable Selector method](DevExpress#5560) [danielroe](https://github.com/danielroe) - [Use polyfill if `location.origin` doesn't exist (in IE11)](DevExpress/testcafe-hammerhead#2441)
[AlexanderMoiseev](https://github.com/AlexanderMoiseev) [augustomezencio-hotmart](https://github.com/augustomezencio-hotmart) - [Fix tree-kill vulnerability from old version.](DevExpress#5690) [bdwain](https://github.com/bdwain) - [Fixes header types for request and response mocks (DevExpress#5529)](DevExpress#5530) [mostlyfabulous](https://github.com/mostlyfabulous) - [Gh2172 Add `ShadowRoot()` as a chainable Selector method](DevExpress#5560) [danielroe](https://github.com/danielroe) - [Use polyfill if `location.origin` doesn't exist (in IE11)](DevExpress/testcafe-hammerhead#2441)
[AlexanderMoiseev](https://github.com/AlexanderMoiseev) [augustomezencio-hotmart](https://github.com/augustomezencio-hotmart) - [Fix tree-kill vulnerability from old version.](#5690) [bdwain](https://github.com/bdwain) - [Fixes header types for request and response mocks (#5529)](#5530) [mostlyfabulous](https://github.com/mostlyfabulous) - [Gh2172 Add `ShadowRoot()` as a chainable Selector method](#5560) [danielroe](https://github.com/danielroe) - [Use polyfill if `location.origin` doesn't exist (in IE11)](DevExpress/testcafe-hammerhead#2441)
Purpose
Extend the
Selector
API to have ashadowRoot
function that returns the elements inside theshadowRoot
when the shadow DOM isopen
. These elements are only otherwise accessible with theshadowRoot
property when using statements likedocument.querySelector('css-selector').shadowRoot.querySelectorAll('css-selector');
in aSelector
, but this createsSelector
chaining problems if there are child/nested elements with ashadowRoot
on them as well.e.g.
Selector('elem-with-shadowRoot').child('p').shadowRoot.withText('text');
will not work.This PR should let developers chain existing
Selector
statements that target elements in theshadowRoot
.Approach
Add a new API
shadowRoot
that can be applied to aSelector
which returns the contents of an element'sshadowRoot
if it exists andnull
otherwise.References
#2172
https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM
Pre-Merge TODO