Skip to content

Commit cecf1de

Browse files
Merge branch 'trunk' into update
2 parents da23401 + a7c0cfb commit cecf1de

File tree

5 files changed

+814
-383
lines changed

5 files changed

+814
-383
lines changed

dotnet/src/webdriver/Firefox/FirefoxExtension.cs

Lines changed: 18 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
using System.Text.Json.Nodes;
2626
using System.Xml;
2727

28-
28+
#nullable enable
2929

3030
namespace OpenQA.Selenium.Firefox
3131
{
@@ -38,8 +38,8 @@ public class FirefoxExtension
3838
private const string RdfManifestFileName = "install.rdf";
3939
private const string JsonManifestFileName = "manifest.json";
4040

41-
private string extensionFileName;
42-
private string extensionResourceId;
41+
private readonly string extensionFileName;
42+
private readonly string extensionResourceId;
4343

4444
/// <summary>
4545
/// Initializes a new instance of the <see cref="FirefoxExtension"/> class.
@@ -48,6 +48,7 @@ public class FirefoxExtension
4848
/// <remarks>WebDriver attempts to resolve the <paramref name="fileName"/> parameter
4949
/// by looking first for the specified file in the directory of the calling assembly,
5050
/// then using the full path to the file, if a full path is provided.</remarks>
51+
/// <exception cref="ArgumentNullException">If <paramref name="fileName"/> is <see langword="null"/>.</exception>
5152
public FirefoxExtension(string fileName)
5253
: this(fileName, string.Empty)
5354
{
@@ -65,16 +66,18 @@ public FirefoxExtension(string fileName)
6566
/// not found in the file system, WebDriver attempts to locate a resource in the
6667
/// executing assembly with the name specified by the <paramref name="resourceId"/>
6768
/// parameter.</remarks>
69+
/// <exception cref="ArgumentNullException">If <paramref name="fileName"/> or <paramref name="resourceId"/> are <see langword="null"/>.</exception>
6870
internal FirefoxExtension(string fileName, string resourceId)
6971
{
70-
this.extensionFileName = fileName;
71-
this.extensionResourceId = resourceId;
72+
this.extensionFileName = fileName ?? throw new ArgumentNullException(nameof(fileName));
73+
this.extensionResourceId = resourceId ?? throw new ArgumentNullException(nameof(resourceId));
7274
}
7375

7476
/// <summary>
7577
/// Installs the extension into a profile directory.
7678
/// </summary>
7779
/// <param name="profileDirectory">The Firefox profile directory into which to install the extension.</param>
80+
/// <exception cref="ArgumentNullException">If <paramref name="profileDirectory"/> is <see langword="null"/>.</exception>
7881
public void Install(string profileDirectory)
7982
{
8083
DirectoryInfo info = new DirectoryInfo(profileDirectory);
@@ -132,7 +135,7 @@ private static string GetExtensionId(string root)
132135

133136
private static string ReadIdFromInstallRdf(string root)
134137
{
135-
string id = null;
138+
string id;
136139
string installRdf = Path.Combine(root, "install.rdf");
137140
try
138141
{
@@ -143,11 +146,11 @@ private static string ReadIdFromInstallRdf(string root)
143146
rdfNamespaceManager.AddNamespace("em", EmNamespaceUri);
144147
rdfNamespaceManager.AddNamespace("RDF", "http://www.w3.org/1999/02/22-rdf-syntax-ns#");
145148

146-
XmlNode node = rdfXmlDocument.SelectSingleNode("//em:id", rdfNamespaceManager);
149+
XmlNode? node = rdfXmlDocument.SelectSingleNode("//em:id", rdfNamespaceManager);
147150
if (node == null)
148151
{
149-
XmlNode descriptionNode = rdfXmlDocument.SelectSingleNode("//RDF:Description", rdfNamespaceManager);
150-
XmlAttribute attribute = descriptionNode.Attributes["id", EmNamespaceUri];
152+
XmlNode? descriptionNode = rdfXmlDocument.SelectSingleNode("//RDF:Description", rdfNamespaceManager);
153+
XmlAttribute? attribute = descriptionNode?.Attributes?["id", EmNamespaceUri];
151154
if (attribute == null)
152155
{
153156
throw new WebDriverException("Cannot locate node containing extension id: " + installRdf);
@@ -175,26 +178,19 @@ private static string ReadIdFromInstallRdf(string root)
175178

176179
private static string ReadIdFromManifestJson(string root)
177180
{
178-
string id = null;
181+
string id = string.Empty;
179182
string manifestJsonPath = Path.Combine(root, JsonManifestFileName);
183+
180184
var manifestObject = JsonNode.Parse(File.ReadAllText(manifestJsonPath));
181-
if (manifestObject["applications"] != null)
185+
if (manifestObject!["applications"]?["gecko"]?["id"] is { } idNode)
182186
{
183-
var applicationObject = manifestObject["applications"];
184-
if (applicationObject["gecko"] != null)
185-
{
186-
var geckoObject = applicationObject["gecko"];
187-
if (geckoObject["id"] != null)
188-
{
189-
id = geckoObject["id"].ToString().Trim();
190-
}
191-
}
187+
id = idNode.ToString().Trim();
192188
}
193189

194190
if (string.IsNullOrEmpty(id))
195191
{
196-
string addInName = manifestObject["name"].ToString().Replace(" ", "");
197-
string addInVersion = manifestObject["version"].ToString();
192+
string addInName = manifestObject["name"]!.ToString().Replace(" ", "");
193+
string addInVersion = manifestObject["version"]!.ToString();
198194
id = string.Format(CultureInfo.InvariantCulture, "{0}@{1}", addInName, addInVersion);
199195
}
200196

dotnet/src/webdriver/Firefox/FirefoxProfile.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,8 +114,14 @@ public static FirefoxProfile FromBase64String(string base64)
114114
/// Adds a Firefox Extension to this profile
115115
/// </summary>
116116
/// <param name="extensionToInstall">The path to the new extension</param>
117+
/// <exception cref="ArgumentNullException">If <paramref name="extensionToInstall"/> is <see langword="null"/>.</exception>
117118
public void AddExtension(string extensionToInstall)
118119
{
120+
if (extensionToInstall is null)
121+
{
122+
throw new ArgumentNullException(nameof(extensionToInstall));
123+
}
124+
119125
this.extensions.Add(Path.GetFileNameWithoutExtension(extensionToInstall), new FirefoxExtension(extensionToInstall));
120126
}
121127

py/selenium/webdriver/common/actions/action_builder.py

Lines changed: 90 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,17 @@ def __init__(
4949
self.driver = driver
5050

5151
def get_device_with(self, name: str) -> Optional[Union["WheelInput", "PointerInput", "KeyInput"]]:
52+
"""Get the device with the given name.
53+
54+
Parameters:
55+
----------
56+
name : str
57+
The name of the device to get.
58+
59+
Returns:
60+
--------
61+
Optional[Union[WheelInput, PointerInput, KeyInput]] : The device with the given name.
62+
"""
5263
return next(filter(lambda x: x == name, self.devices), None)
5364

5465
@property
@@ -72,21 +83,83 @@ def wheel_action(self) -> WheelActions:
7283
return self._wheel_action
7384

7485
def add_key_input(self, name: str) -> KeyInput:
86+
"""Add a new key input device to the action builder.
87+
88+
Parameters:
89+
----------
90+
name : str
91+
The name of the key input device.
92+
93+
Returns:
94+
--------
95+
KeyInput : The newly created key input device.
96+
97+
Example:
98+
--------
99+
>>> action_builder = ActionBuilder(driver)
100+
>>> action_builder.add_key_input(name="keyboard2")
101+
"""
75102
new_input = KeyInput(name)
76103
self._add_input(new_input)
77104
return new_input
78105

79106
def add_pointer_input(self, kind: str, name: str) -> PointerInput:
107+
"""Add a new pointer input device to the action builder.
108+
109+
Parameters:
110+
----------
111+
kind : str
112+
The kind of pointer input device.
113+
- "mouse"
114+
- "touch"
115+
- "pen"
116+
name : str
117+
The name of the pointer input device.
118+
119+
Returns:
120+
--------
121+
PointerInput : The newly created pointer input device.
122+
123+
Example:
124+
--------
125+
>>> action_builder = ActionBuilder(driver)
126+
>>> action_builder.add_pointer_input(kind="mouse", name="mouse")
127+
"""
80128
new_input = PointerInput(kind, name)
81129
self._add_input(new_input)
82130
return new_input
83131

84132
def add_wheel_input(self, name: str) -> WheelInput:
133+
"""Add a new wheel input device to the action builder.
134+
135+
Parameters:
136+
----------
137+
name : str
138+
The name of the wheel input device.
139+
140+
Returns:
141+
--------
142+
WheelInput : The newly created wheel input device.
143+
144+
Example:
145+
--------
146+
>>> action_builder = ActionBuilder(driver)
147+
>>> action_builder.add_wheel_input(name="wheel2")
148+
"""
85149
new_input = WheelInput(name)
86150
self._add_input(new_input)
87151
return new_input
88152

89153
def perform(self) -> None:
154+
"""Performs all stored actions.
155+
156+
Example:
157+
--------
158+
>>> action_builder = ActionBuilder(driver)
159+
>>> keyboard = action_builder.key_input
160+
>>> el = driver.find_element(id: "some_id")
161+
>>> action_builder.click(el).pause(keyboard).pause(keyboard).pause(keyboard).send_keys('keys').perform()
162+
"""
90163
enc = {"actions": []}
91164
for device in self.devices:
92165
encoded = device.encode()
@@ -96,8 +169,24 @@ def perform(self) -> None:
96169
self.driver.execute(Command.W3C_ACTIONS, enc)
97170

98171
def clear_actions(self) -> None:
99-
"""Clears actions that are already stored on the remote end."""
172+
"""Clears actions that are already stored on the remote end.
173+
174+
Example:
175+
--------
176+
>>> action_builder = ActionBuilder(driver)
177+
>>> keyboard = action_builder.key_input
178+
>>> el = driver.find_element(By.ID, "some_id")
179+
>>> action_builder.click(el).pause(keyboard).pause(keyboard).pause(keyboard).send_keys('keys')
180+
>>> action_builder.clear_actions()
181+
"""
100182
self.driver.execute(Command.W3C_CLEAR_ACTIONS)
101183

102184
def _add_input(self, new_input: Union[KeyInput, PointerInput, WheelInput]) -> None:
185+
"""Add a new input device to the action builder.
186+
187+
Parameters:
188+
----------
189+
new_input : Union[KeyInput, PointerInput, WheelInput]
190+
The new input device to add.
191+
"""
103192
self.devices.append(new_input)

0 commit comments

Comments
 (0)