Skip to content

Commit 201fad3

Browse files
committed
[dotnet] Handle returning shadow roots from JavaScript
1 parent 9cd6c45 commit 201fad3

19 files changed

+277
-157
lines changed

common/src/web/shadowRootPage.html

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>Shadow Root Page</title>
5+
</head>
6+
<body>
7+
<style>
8+
custom-checkbox-element {
9+
display:block; width:20px; height:20px;
10+
}
11+
</style>
12+
<div><input id="noShadowRoot" /></div>
13+
<div><custom-checkbox-element></custom-checkbox-element></div>
14+
<script>
15+
customElements.define('custom-checkbox-element',
16+
class extends HTMLElement {
17+
constructor() {
18+
super();
19+
this.attachShadow({mode: 'open'}).innerHTML = '<div><input type="checkbox"/></div>';
20+
}
21+
}
22+
);
23+
</script>
24+
</body>
25+
</html>

dotnet/src/webdriver/ElementCoordinates.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ public object AuxiliaryLocator
7070
{
7171
get
7272
{
73-
IWebElementReference elementReference = this.element as IWebElementReference;
73+
IWebDriverObjectReference elementReference = this.element as IWebDriverObjectReference;
7474
if (elementReference == null)
7575
{
7676
return null;
@@ -80,7 +80,7 @@ public object AuxiliaryLocator
8080
// uses the raw ID of the element, not an element reference. To use this,
8181
// extract the ID using the well-known key to the dictionary for element
8282
// references.
83-
return elementReference.ElementReferenceId;
83+
return elementReference.ObjectReferenceId;
8484
}
8585
}
8686
}

dotnet/src/webdriver/Interactions/PointerInputDevice.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -521,13 +521,13 @@ public override string ToString()
521521

522522
private Dictionary<string, object> ConvertElement()
523523
{
524-
IWebElementReference elementReference = this.target as IWebElementReference;
524+
IWebDriverObjectReference elementReference = this.target as IWebDriverObjectReference;
525525
if (elementReference == null)
526526
{
527527
IWrapsElement elementWrapper = this.target as IWrapsElement;
528528
if (elementWrapper != null)
529529
{
530-
elementReference = elementWrapper.WrappedElement as IWebElementReference;
530+
elementReference = elementWrapper.WrappedElement as IWebDriverObjectReference;
531531
}
532532
}
533533

dotnet/src/webdriver/Interactions/WheelInputDevice.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,13 +178,13 @@ public override Dictionary<string, object> ToDictionary()
178178

179179
private Dictionary<string, object> ConvertElement()
180180
{
181-
IWebElementReference elementReference = this.target as IWebElementReference;
181+
IWebDriverObjectReference elementReference = this.target as IWebDriverObjectReference;
182182
if (elementReference == null)
183183
{
184184
IWrapsElement elementWrapper = this.target as IWrapsElement;
185185
if (elementWrapper != null)
186186
{
187-
elementReference = elementWrapper.WrappedElement as IWebElementReference;
187+
elementReference = elementWrapper.WrappedElement as IWebDriverObjectReference;
188188
}
189189
}
190190

dotnet/src/webdriver/Internal/IWebElementReference.cs renamed to dotnet/src/webdriver/Internal/IWebDriverObjectReference.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// <copyright file="IWebElementReference.cs" company="WebDriver Committers">
1+
// <copyright file="IWebElementReference.cs" company="WebDriver Committers">
22
// Licensed to the Software Freedom Conservancy (SFC) under one
33
// or more contributor license agreements. See the NOTICE file
44
// distributed with this work for additional information
@@ -26,12 +26,12 @@ namespace OpenQA.Selenium.Internal
2626
/// <summary>
2727
/// Defines the interface through which the framework can serialize an element to the wire protocol.
2828
/// </summary>
29-
internal interface IWebElementReference
29+
internal interface IWebDriverObjectReference
3030
{
3131
/// <summary>
32-
/// Gets the internal ID of the element.
32+
/// Gets the internal ID of the WebDriver object.
3333
/// </summary>
34-
string ElementReferenceId { get; }
34+
string ObjectReferenceId { get; }
3535

3636
/// <summary>
3737
/// Converts an object into an object that represents an element for the wire protocol.

dotnet/src/webdriver/ShadowRoot.cs

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,14 @@
1919
using System;
2020
using System.Collections.Generic;
2121
using System.Collections.ObjectModel;
22+
using OpenQA.Selenium.Internal;
2223

2324
namespace OpenQA.Selenium
2425
{
2526
/// <summary>
2627
/// Provides a representation of an element's shadow root.
2728
/// </summary>
28-
public class ShadowRoot : ISearchContext, IWrapsDriver
29+
public class ShadowRoot : ISearchContext, IWrapsDriver, IWebDriverObjectReference
2930
{
3031
/// <summary>
3132
/// The property name that represents an element shadow root in the wire protocol.
@@ -54,6 +55,29 @@ public IWebDriver WrappedDriver
5455
get { return this.driver; }
5556
}
5657

58+
/// <summary>
59+
/// Gets the internal ID for this ShadowRoot.
60+
/// </summary>
61+
string IWebDriverObjectReference.ObjectReferenceId
62+
{
63+
get { return this.shadowRootId; }
64+
}
65+
66+
internal static bool ContainsShadowRootReference(Dictionary<string, object> shadowRootDictionary)
67+
{
68+
if (shadowRootDictionary == null)
69+
{
70+
throw new ArgumentNullException(nameof(shadowRootDictionary), "The dictionary containing the shadow root reference cannot be null");
71+
}
72+
73+
return shadowRootDictionary.ContainsKey(ShadowRootReferencePropertyName);
74+
}
75+
76+
internal static ShadowRoot FromDictionary(WebDriver driver, Dictionary<string, object> shadowRootDictionary)
77+
{
78+
return new ShadowRoot(driver, shadowRootDictionary[ShadowRoot.ShadowRootReferencePropertyName].ToString());
79+
}
80+
5781
/// <summary>
5882
/// Finds the first <see cref="IWebElement"/> using the given method.
5983
/// </summary>
@@ -96,5 +120,12 @@ public ReadOnlyCollection<IWebElement> FindElements(By by)
96120
Response commandResponse = this.driver.InternalExecute(DriverCommand.FindShadowChildElements, parameters);
97121
return this.driver.GetElementsFromResponse(commandResponse);
98122
}
123+
124+
Dictionary<string, object> IWebDriverObjectReference.ToDictionary()
125+
{
126+
Dictionary<string, object> shadowRootDictionary = new Dictionary<string, object>();
127+
shadowRootDictionary.Add(ShadowRootReferencePropertyName, this.shadowRootId);
128+
return shadowRootDictionary;
129+
}
99130
}
100131
}

dotnet/src/webdriver/TargetLocator.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -91,13 +91,13 @@ public IWebDriver Frame(IWebElement frameElement)
9191
throw new ArgumentNullException(nameof(frameElement), "Frame element cannot be null");
9292
}
9393

94-
IWebElementReference elementReference = frameElement as IWebElementReference;
94+
IWebDriverObjectReference elementReference = frameElement as IWebDriverObjectReference;
9595
if (elementReference == null)
9696
{
9797
IWrapsElement elementWrapper = frameElement as IWrapsElement;
9898
if (elementWrapper != null)
9999
{
100-
elementReference = elementWrapper.WrappedElement as IWebElementReference;
100+
elementReference = elementWrapper.WrappedElement as IWebDriverObjectReference;
101101
}
102102
}
103103

@@ -108,7 +108,7 @@ public IWebDriver Frame(IWebElement frameElement)
108108

109109
// TODO: Remove "ELEMENT" addition when all remote ends are spec-compliant.
110110
Dictionary<string, object> elementDictionary = elementReference.ToDictionary();
111-
elementDictionary.Add("ELEMENT", elementReference.ElementReferenceId);
111+
elementDictionary.Add("ELEMENT", elementReference.ObjectReferenceId);
112112

113113
Dictionary<string, object> parameters = new Dictionary<string, object>();
114114
parameters.Add("id", elementDictionary);

dotnet/src/webdriver/WebDriver.cs

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -940,13 +940,13 @@ protected object ExecuteScriptCommand(string script, string commandName, params
940940
private static object ConvertObjectToJavaScriptObject(object arg)
941941
{
942942
IWrapsElement argAsWrapsElement = arg as IWrapsElement;
943-
IWebElementReference argAsElementReference = arg as IWebElementReference;
943+
IWebDriverObjectReference argAsObjectReference = arg as IWebDriverObjectReference;
944944
IEnumerable argAsEnumerable = arg as IEnumerable;
945945
IDictionary argAsDictionary = arg as IDictionary;
946946

947-
if (argAsElementReference == null && argAsWrapsElement != null)
947+
if (argAsObjectReference == null && argAsWrapsElement != null)
948948
{
949-
argAsElementReference = argAsWrapsElement.WrappedElement as IWebElementReference;
949+
argAsObjectReference = argAsWrapsElement.WrappedElement as IWebDriverObjectReference;
950950
}
951951

952952
object converted = null;
@@ -955,11 +955,11 @@ private static object ConvertObjectToJavaScriptObject(object arg)
955955
{
956956
converted = arg;
957957
}
958-
else if (argAsElementReference != null)
958+
else if (argAsObjectReference != null)
959959
{
960960
// TODO: Remove "ELEMENT" addition when all remote ends are spec-compliant.
961-
Dictionary<string, object> elementDictionary = argAsElementReference.ToDictionary();
962-
converted = elementDictionary;
961+
Dictionary<string, object> webDriverObjectReferenceDictionary = argAsObjectReference.ToDictionary();
962+
converted = webDriverObjectReferenceDictionary;
963963
}
964964
else if (argAsDictionary != null)
965965
{
@@ -1026,6 +1026,10 @@ private object ParseJavaScriptReturnValue(object responseValue)
10261026
{
10271027
returnValue = this.elementFactory.CreateElement(resultAsDictionary);
10281028
}
1029+
else if (ShadowRoot.ContainsShadowRootReference(resultAsDictionary))
1030+
{
1031+
returnValue = ShadowRoot.FromDictionary(this, resultAsDictionary);
1032+
}
10291033
else
10301034
{
10311035
// Recurse through the dictionary, re-parsing each value.

dotnet/src/webdriver/WebElement.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@
2929

3030
namespace OpenQA.Selenium
3131
{
32-
public class WebElement : IWebElement, IFindsElement, IWrapsDriver, ILocatable, ITakesScreenshot, IWebElementReference
32+
public class WebElement : IWebElement, IFindsElement, IWrapsDriver, ILocatable, ITakesScreenshot, IWebDriverObjectReference
3333
{
3434
/// <summary>
3535
/// The property name that represents a web element in the wire protocol.
@@ -250,7 +250,7 @@ public virtual ICoordinates Coordinates
250250
/// <summary>
251251
/// Gets the internal ID of the element.
252252
/// </summary>
253-
string IWebElementReference.ElementReferenceId
253+
string IWebDriverObjectReference.ObjectReferenceId
254254
{
255255
get { return this.elementId; }
256256
}
@@ -695,7 +695,7 @@ public override bool Equals(object obj)
695695
return false;
696696
}
697697

698-
Dictionary<string, object> IWebElementReference.ToDictionary()
698+
Dictionary<string, object> IWebDriverObjectReference.ToDictionary()
699699
{
700700
Dictionary<string, object> elementDictionary = new Dictionary<string, object>();
701701
elementDictionary.Add(ElementReferencePropertyName, this.elementId);
@@ -753,9 +753,10 @@ private string UploadFile(string localFile)
753753
throw new WebDriverException("Cannot upload " + localFile, e);
754754
}
755755
}
756-
private IWebElementReference ToElementReference()
756+
757+
private IWebDriverObjectReference ToElementReference()
757758
{
758-
return this as IWebElementReference;
759+
return this as IWebDriverObjectReference;
759760
}
760761
}
761762
}

dotnet/test/common/DevTools/DevToolsConsoleTest.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,11 @@ public class DevToolsConsoleTest : DevToolsTestFixture
1919
[IgnoreBrowser(Selenium.Browser.Safari, "Safari does not support Chrome DevTools Protocol")]
2020
public async Task VerifyMessageAdded()
2121
{
22-
var domains = session.GetVersionSpecificDomains<V93.DevToolsSessionDomains>();
22+
var domains = session.GetVersionSpecificDomains<V96.DevToolsSessionDomains>();
2323
string consoleMessage = "Hello Selenium";
2424

2525
ManualResetEventSlim sync = new ManualResetEventSlim(false);
26-
EventHandler<V93.Console.MessageAddedEventArgs> messageAddedHandler = (sender, e) =>
26+
EventHandler<V96.Console.MessageAddedEventArgs> messageAddedHandler = (sender, e) =>
2727
{
2828
Assert.That(e.Message.Text, Is.EqualTo(consoleMessage));
2929
sync.Set();

0 commit comments

Comments
 (0)