selenium icon indicating copy to clipboard operation
selenium copied to clipboard

[🐛 Bug]: Displayed property of WebElement outputs incorrectly when using ShadowRoot

Open SitrucHtims opened this issue 1 year ago • 8 comments

What happened?

When evaluating the Displayed property of the WebElement. Displayed returns False, but should return True as the element is displayed.

To use the below PowerShell code sample, save the script to a directory that also contains the WebDriver.dll and desired browserdriver.exe

---PowerShell code sample did not display correctly, so I attached as .txt file (Also included in the "How can we reproduce the issue" section--- Example.txt

Execution of the Example outputs: image

Notice Displayed is False; yet on the page, the element is definitely displayed. image

I have investigated and the issue seems to come from the use of ShadowRoot on the page and is-Displayed.js not able to correctly evaluate it.

The input element that we are checking the Displayed property on hosts a shadow-root image

When is-displayed.js evaluates the element, it begins evaluating each element up the tree to the root element. If it were the normal DOM, it would reach the #document element and see this is nodeType 9 and return true if all elements are visible up the tree. In this case, when is-displayed.js begins going up the tree it reaches the "dnx-testfield" which is seen as the shadowRoot. In the case of this page, there is no assignedSlot for the shadowRoot, so null is returned and since null is returned, False is returned for displayed.

This can be seen in the below code; however, I only have the minified .js to work with, so it's a little hard to read.  function c(d) {   if (W(d) && "none" == Y(d, "display"))   return !1;   var e;   if ((e = d.parentNode) && e.shadowRoot && void 0 !== d.assignedSlot)   e = d.assignedSlot ? d.assignedSlot.parentNode : null;   else if (d.getDestinationInsertionPoints) {   var f = d.getDestinationInsertionPoints();   0 < f.length && (e = f[f.length - 1])   }   if (Fc && e instanceof ShadowRoot) {   if (e.host.shadowRoot !== e)   return !1;   e = e.host   }   return !e || 9 != e.nodeType && 11 != e.nodeType ? e && W(e, "DETAILS") && !e.open && !W(d, "SUMMARY") ? !1 : !!e && c(e) : !0  }

In the page when a parent element with a populated shadowRoot property is reached, it goes in the this block of code:   if ((e = d.parentNode) && e.shadowRoot && void 0 !== d.assignedSlot)   e = d.assignedSlot ? d.assignedSlot.parentNode : null;

In the page, the parent element with shadowRoot is dnx.textfield with label "Email" image

When this is reached e is set to null because d.assignedSlot (the assignedSlot property value of the current element) is null

Then since e is null and e (the parent element is not type 9 or 11), then it does not return True as it should since the shadowRoot has been reached.   return !e || 9 != e.nodeType && 11 != e.nodeType ? e && W(e, "DETAILS") && !e.open && !W(d, "SUMMARY") ? !1 : !!e && c(e) : !0

It may not be the right solution, but I was able to address this by adding a conditional to the return that if the parent element matched the parent elements shadowroot property, then return the parent element instead of null when there is no assignedSlot.   if ((e = d.parentNode) && e.shadowRoot && void 0 !== d.assignedSlot)   e = d.assignedSlot ? d.assignedSlot.parentNode : d.parentNode == d.parentNode.shadowRoot ? d.parentNode : null;   else if (d.getDestinationInsertionPoints) {   var f = d.getDestinationInsertionPoints();   0 < f.length && (e = f[f.length - 1])   }

How can we reproduce the issue?

Function Get-Browser {
    Param (
           [Parameter(Mandatory=$true)]
           [ValidateSet("Edge","Chrome")]
           [string]$type
          )
    
    Set-EnvironmentPath

    Add-Type -Path "$($PSScriptRoot)\WebDriver.dll"

    Switch ($type) {
          "edge" {
                  $Driver = New-Object OpenQA.Selenium.Edge.EdgeDriver
                 }
        "chrome" {
                  $Driver = New-Object OpenQA.Selenium.Chrome.ChromeDriver
                 }
    }
    $Driver
}

Relevant log output

Unfortunately I was unable to find a good example of enabling logging with PowerShell, and the logging namespace did not show under OpenQA.Selenium.Internal, so I was not able to include this.

Operating System

Windows 10

Selenium version

PowerShell 5.1.19041.1682

What are the browser(s) and version(s) where you see this issue?

Chrome 121.0.6167.185 and Edge 121.0.2277.128 (both 64-bit)

What are the browser driver(s) and version(s) where you see this issue?

ChromeDriver 120.0.6099.109 (3419140ab665596f21b385ce136419fde0924272-refs/branch-heads/6099@{#1483}) Microsoft Edge WebDriver 120.0.2210.121 (6086ec26a02a23b6723b794ef7b81d37e71506e3)

Are you using Selenium Grid?

No

SitrucHtims avatar Feb 23 '24 22:02 SitrucHtims

@SitrucHtims, thank you for creating this issue. We will troubleshoot it as soon as we can.


Info for maintainers

Triage this issue by using labels.

If information is missing, add a helpful comment and then I-issue-template label.

If the issue is a question, add the I-question label.

If the issue is valid but there is no time to troubleshoot it, consider adding the help wanted label.

If the issue requires changes or fixes from an external project (e.g., ChromeDriver, GeckoDriver, MSEdgeDriver, W3C), add the applicable G-* label, and it will provide the correct link and auto-close the issue.

After troubleshooting the issue, please add the R-awaiting answer label.

Thank you!

github-actions[bot] avatar Feb 23 '24 22:02 github-actions[bot]

Sorry looks like the PowerShell script in the "How can we reproduce the issue?" section is cut off, but the full script is attached as a .txt file in the "What happened?" section

SitrucHtims avatar Feb 23 '24 22:02 SitrucHtims

Does this happen in Firefox, Safari, and Edge as well?

diemol avatar Feb 27 '24 15:02 diemol

I know it happens with Chrome and Edge, I can check for FF, but don't have a system to check Safari.

SitrucHtims avatar Feb 27 '24 16:02 SitrucHtims

Can you check? This would hint if it is a ChromeDriver issue or a WebDriver issue.

diemol avatar Feb 27 '24 16:02 diemol

I can confirm the behavior happens for Chrome, Edge, and FireFox. I am unsure about Safari as I do not have a system to test with.

SitrucHtims avatar Feb 27 '24 17:02 SitrucHtims

It could actually be that the flow is never intended to reach this line of execution and getting there unintentionally.

if ((e = d.parentNode) && e.shadowRoot && void 0 !== d.assignedSlot) e = d.assignedSlot ? d.assignedSlot.parentNode : null; else if (d.getDestinationInsertionPoints) { var f = d.getDestinationInsertionPoints(); 0 < f.length && (e = f[f.length - 1]) }

void 0 !== d.assignedSlot appears to be checking to see if d.assignedSlot has a value or not, but it's using !== which also checks the data type, and null is not equal to undefined from a data type perspective.

IE: undefined !== null true undefined != null false

Since d.assignedSlot is null, maybe it is intended to skip this and the solution would simply be to change the condition: from: void 0 !== d.assignedSlot to: void 0 != d.assignedSlot

SitrucHtims avatar Feb 28 '24 19:02 SitrucHtims

This issue is looking for contributors.

Please comment below or reach out to us through our IRC/Slack/Matrix channels if you are interested.

github-actions[bot] avatar Mar 08 '24 23:03 github-actions[bot]