-
-
Notifications
You must be signed in to change notification settings - Fork 8.6k
.pr_agent_auto_best_practices
Pattern 1: Add null checks and validation for parameters and variables before using them to prevent NullReferenceException, KeyError, or similar runtime errors. This includes checking dictionary keys exist before accessing them and validating that required fields are present.
Example code before:
var result = dictionary[key];
var value = response.data.field;
Example code after:
if (dictionary.TryGetValue(key, out var result)) {
// use result
}
var value = response.data?.field ?? defaultValue;
Relevant past accepted suggestions:
Suggestion 1:
Add enum validation before string conversion
Add validation to ensure the enum value is defined before converting to string. This prevents potential issues if an invalid enum value is somehow assigned to LogLevel.
dotnet/src/webdriver/Chromium/ChromiumDriverService.cs [162-165]
if (this.LogLevel != ChromiumDriverLogLevel.Default)
{
- argsBuilder.Append(string.Format(CultureInfo.InvariantCulture, " --log-level={0}", this.LogLevel.ToString().ToUpperInvariant()));
+ if (Enum.IsDefined(typeof(ChromiumDriverLogLevel), this.LogLevel))
+ {
+ argsBuilder.Append($" --log-level={this.LogLevel.ToString().ToUpperInvariant()}");
+ }
}
Suggestion 2:
Handle potential None from regex
The regex search could return None if the pattern doesn't match, causing an AttributeError when accessing index [1]. Add a check to handle cases where the URL format doesn't match the expected pattern.
scripts/update_multitool_binaries.py [40-42]
-version = re.search(f"download/(.*?)/{tool}", data[tool]["binaries"][0]["url"])[
- 1
-]
+version_match = re.search(f"download/(.*?)/{tool}", data[tool]["binaries"][0]["url"])
+if not version_match:
+ continue
+version = version_match[1]
Suggestion 3:
Add null validation for directory
The currentDirectory variable should be validated for null before being used in Path.Combine() calls. Add a null check to prevent potential NullReferenceException if AppContext.BaseDirectory returns null.
dotnet/src/webdriver/SeleniumManager.cs [82-89]
+ArgumentNullException.ThrowIfNull(currentDirectory);
+
binaryFullPath = platform switch
{
SupportedPlatform.Windows => Path.Combine(currentDirectory, "runtimes", "win", "native", "selenium-manager.exe"),
SupportedPlatform.Linux => Path.Combine(currentDirectory, "runtimes", "linux", "native", "selenium-manager"),
SupportedPlatform.MacOS => Path.Combine(currentDirectory, "runtimes", "osx", "native", "selenium-manager"),
_ => throw new PlatformNotSupportedException(
$"Selenium Manager doesn't support your runtime platform: {RuntimeInformation.OSDescription}"),
};
Suggestion 4:
Add missing null check validation
Add null check for clientConfig parameter to maintain consistency with other parameter validations. The method handles null options and service but doesn't validate clientConfig which could cause issues downstream.
java/src/org/openqa/selenium/ie/InternetExplorerDriver.java [111-119]
public InternetExplorerDriver(
@Nullable InternetExplorerDriverService service,
@Nullable InternetExplorerOptions options,
@Nullable ClientConfig clientConfig) {
if (options == null) {
options = new InternetExplorerOptions();
}
if (service == null) {
service = InternetExplorerDriverService.createDefaultService();
+ }
+ if (clientConfig == null) {
+ clientConfig = ClientConfig.defaultConfig();
+ }
Suggestion 5:
Validate required JSON fields
The from_json method should validate that required fields (realm, origin, type) are present in the JSON data. Currently, it allows None values for required fields which could cause issues downstream.
py/selenium/webdriver/common/bidi/script.py [57-75]
@classmethod
def from_json(cls, json: dict) -> "RealmInfo":
"""Creates a RealmInfo instance from a dictionary.
Parameters:
-----------
json: A dictionary containing the realm information.
Returns:
-------
RealmInfo: A new instance of RealmInfo.
"""
+ if not json.get("realm") or not json.get("origin") or not json.get("type"):
+ raise ValueError("Required fields 'realm', 'origin', and 'type' must be present")
+
return cls(
realm=json.get("realm"),
origin=json.get("origin"),
type=json.get("type"),
context=json.get("context"),
sandbox=json.get("sandbox"),
)
Suggestion 6:
Prevent potential KeyError
**params))
-
del self.subscriptions[event_name]
-
if event_name in self.subscriptions:
-
callbacks = self.subscriptions[event_name]
-
if callback_id in callbacks:
-
callbacks.remove(callback_id)
-
if not callbacks:
-
params = {"events": [event_name]}
-
session = Session(self.conn)
-
self.conn.execute(session.unsubscribe(**params))
-
del self.subscriptions[event_name]
**The code attempts to access self.subscriptions[event_name] after checking if event_name is in self.subscriptions, but then immediately accesses it again on the next line without checking. This could cause a KeyError if event_name is not in self.subscriptions.**
[py/selenium/webdriver/common/bidi/browsing_context.py [716-718]](https://github.com/SeleniumHQ/selenium/pull/15848/files#diff-a65d02c951aeb477672aa52e5eb0106645ba869aa186c0af6d2672c42cac95c6R716-R718)
```diff
+ self.conn.remove_callback(event_obj, callback_id)
+ if event_name in self.subscriptions and callback_id in self.subscriptions[event_name]:
+ self.subscriptions[event_name].remove(callback_id)
++ if len(self.subscriptions[event_name]) == 0:
++ params = {"events": [event_name]}
++ session = Session(self.conn)
++ self.conn.execute(session.unsubscribe(**params))
++ del self.subscriptions[event_name]
Suggestion 7:
Prevent ValueError on removal
Check if the callback_id exists in the subscriptions before attempting to remove it. The current implementation will raise a ValueError if the callback_id is not in the list, which could happen if it was already removed or never added.
py/selenium/webdriver/common/bidi/browsing_context.py [716]
def remove_event_handler(self, event: str, callback_id: int) -> None:
"""Remove an event handler from the browsing context.
Parameters:
----------
event: The event to unsubscribe from.
callback_id: The callback id to remove.
"""
try:
event_name = self.EVENTS[event]
except KeyError:
raise Exception(f"Event {event} not found")
event_obj = BrowsingContextEvent(event_name)
self.conn.remove_callback(event_obj, callback_id)
- self.subscriptions[event_name].remove(callback_id)
+ if event_name in self.subscriptions and callback_id in self.subscriptions[event_name]:
+ self.subscriptions[event_name].remove(callback_id)
Suggestion 8:
Check for missing fields
The code uses data.get() which returns None for missing keys, but then checks types without checking for None values. This could lead to misleading error messages when fields are missing versus when they have incorrect types.
py/selenium/webdriver/common/bidi/browser.py [131-146]
try:
client_window = data.get("clientWindow")
+ if client_window is None:
+ raise ValueError("clientWindow is required")
if not isinstance(client_window, str):
raise ValueError("clientWindow must be a string")
state = data.get("state")
+ if state is None:
+ raise ValueError("state is required")
if not isinstance(state, str):
raise ValueError("state must be a string")
width = data.get("width")
+ if width is None:
+ raise ValueError("width is required")
if not isinstance(width, int):
raise ValueError("width must be an integer")
height = data.get("height")
+ if height is None:
+ raise ValueError("height is required")
if not isinstance(height, int):
raise ValueError("height must be an integer")
Suggestion 9:
Check dictionary key exists
The code doesn't check if the successId exists in the _pendingCommands dictionary before accessing it. This could lead to a KeyNotFoundException if a success message is received for a command ID that is not in the dictionary.
dotnet/src/webdriver/BiDi/Communication/Broker.cs [136-142]
try
{
var data = await _transport.ReceiveAsync(cancellationToken).ConfigureAwait(false);
Utf8JsonReader utfJsonReader = new(new ReadOnlySpan<byte>(data));
utfJsonReader.Read();
var messageType = utfJsonReader.GetDiscriminator("type");
switch (messageType)
{
case "success":
var successId = int.Parse(utfJsonReader.GetDiscriminator("id"));
- var successCommand = _pendingCommands[successId];
- var messageSuccess = JsonSerializer.Deserialize(ref utfJsonReader, successCommand.Item1.ResultType, _jsonSerializerContext);
+ if (_pendingCommands.TryGetValue(successId, out var successCommand))
+ {
+ var messageSuccess = JsonSerializer.Deserialize(ref utfJsonReader, successCommand.Item1.ResultType, _jsonSerializerContext);
- successCommand.Item2.SetResult(messageSuccess);
+ successCommand.Item2.SetResult(messageSuccess);
- _pendingCommands.TryRemove(successId, out _);
+ _pendingCommands.TryRemove(successId, out _);
+ }
break;
Suggestion 10:
Check event handlers exist
The code doesn't check if the method exists in the _eventHandlers dictionary or if there are any handlers for that method before accessing it. This could lead to a KeyNotFoundException or InvalidOperationException (when calling First() on an empty collection) if an event is received for a method that has no registered handlers.
dotnet/src/webdriver/BiDi/Communication/Broker.cs [145-159]
case "event":
utfJsonReader.Read();
utfJsonReader.Read();
var method = utfJsonReader.GetString();
utfJsonReader.Read();
- // TODO: Just get type info from existing subscribers, should be better
- var type = _eventHandlers[method].First().EventArgsType;
+ if (_eventHandlers.TryGetValue(method, out var handlers) && handlers.Count > 0)
+ {
+ // TODO: Just get type info from existing subscribers, should be better
+ var type = handlers.First().EventArgsType;
- var eventArgs = (EventArgs)JsonSerializer.Deserialize(ref utfJsonReader, type, _jsonSerializerContext);
+ var eventArgs = (EventArgs)JsonSerializer.Deserialize(ref utfJsonReader, type, _jsonSerializerContext);
- var messageEvent = new MessageEvent(method, eventArgs);
- _pendingEvents.Add(messageEvent);
+ var messageEvent = new MessageEvent(method, eventArgs);
+ _pendingEvents.Add(messageEvent);
+ }
break;
Suggestion 11:
Validate discriminator existence
The method doesn't handle the case where the discriminator property isn't found in the JSON object. If the property doesn't exist, the method will return null, which could lead to unexpected behavior in the converters that use this method. Consider adding validation to throw a more descriptive exception when the discriminator property is missing.
dotnet/src/webdriver/BiDi/Communication/Json/Internal/JsonExtensions.cs [26-52]
public static string? GetDiscriminator(this ref Utf8JsonReader reader, string name)
{
Utf8JsonReader readerClone = reader;
if (readerClone.TokenType != JsonTokenType.StartObject)
throw new JsonException();
string? discriminator = null;
readerClone.Read();
while (readerClone.TokenType == JsonTokenType.PropertyName)
{
string? propertyName = readerClone.GetString();
readerClone.Read();
if (propertyName == name)
{
discriminator = readerClone.GetString();
break;
}
readerClone.Skip();
readerClone.Read();
}
+ if (discriminator == null)
+ throw new JsonException($"Required discriminator property '{name}' not found in JSON object.");
+
return discriminator;
}
Suggestion 12:
Handle potential null string
The RemoteValue.String() method is called with a potentially null string value from GetString(), but the method doesn't appear to handle null values properly. This could lead to a NullReferenceException.
dotnet/src/webdriver/BiDi/Communication/Json/Converters/Polymorphic/RemoteValueConverter.cs [36]
-return RemoteValue.String(jsonDocument.RootElement.GetString());
+return RemoteValue.String(jsonDocument.RootElement.GetString() ?? string.Empty);
Pattern 2: Use proper resource disposal patterns with using statements, try-finally blocks, or explicit cleanup to prevent resource leaks when working with sockets, streams, processes, and other disposable objects.
Example code before:
var socket = new Socket();
socket.Connect(endpoint);
var data = socket.Receive();
socket.Close();
Example code after:
using var socket = new Socket();
try {
socket.Connect(endpoint);
var data = socket.Receive();
} finally {
socket.Close();
}
Relevant past accepted suggestions:
Suggestion 1:
Add exception handling for async operations
The async method lacks exception handling which could cause unhandled exceptions to crash the application. Add try-catch blocks to handle potential I/O exceptions during stream reading and log writing operations.
dotnet/src/webdriver/Firefox/FirefoxDriverService.cs [346-356]
private async Task ReadStreamAsync(StreamReader reader)
{
- string? line;
- while ((line = await reader.ReadLineAsync()) != null)
+ try
{
- if (logWriter != null)
+ string? line;
+ while ((line = await reader.ReadLineAsync()) != null)
{
- logWriter.WriteLine($"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff} {line}");
+ if (logWriter != null)
+ {
+ logWriter.WriteLine($"{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff} {line}");
+ }
}
+ }
+ catch (Exception ex)
+ {
+ // Log or handle the exception appropriately
+ System.Diagnostics.Debug.WriteLine($"Error reading stream: {ex.Message}");
}
}
Suggestion 2:
Set disposed field to null
The disposal logic should set the logWriter field to null after disposing to prevent potential use-after-dispose scenarios. This ensures the field cannot be accessed after disposal.
dotnet/src/webdriver/Firefox/FirefoxDriverService.cs [254-262]
protected override void Dispose(bool disposing)
{
if (logWriter != null && disposing)
{
logWriter.Dispose();
+ logWriter = null;
}
base.Dispose(disposing);
}
Suggestion 3:
Add proper resource disposal handling
The IPv4 fallback listener is not properly disposed if an exception occurs during its operation. Wrap the fallback listener in a using statement or try-finally block to ensure proper resource cleanup.
dotnet/src/webdriver/Internal/PortUtilities.cs [45-53]
catch (SocketException)
{
// If IPv6Any is not supported, fallback to IPv4
var listener = new TcpListener(IPAddress.Any, 0);
- listener.Start();
- int port = ((IPEndPoint)listener.LocalEndpoint).Port;
- listener.Stop();
- return port;
+ try
+ {
+ listener.Start();
+ int port = ((IPEndPoint)listener.LocalEndpoint).Port;
+ return port;
+ }
+ finally
+ {
+ listener.Stop();
+ }
}
Suggestion 4:
Use proper resource disposal patterns
The TcpListener resources are not properly disposed in case of exceptions. Use using statements or try-finally blocks to ensure proper cleanup. This prevents resource leaks if exceptions occur between Start() and Stop() calls.
dotnet/src/webdriver/Internal/PortUtilities.cs [38-43]
-var listener = new TcpListener(IPAddress.IPv6Any, 0);
+using var listener = new TcpListener(IPAddress.IPv6Any, 0);
listener.Server.DualMode = true; // Listen on both IPv4 and IPv6
listener.Start();
int port = ((IPEndPoint)listener.LocalEndpoint).Port;
-listener.Stop();
return port;
Suggestion 5:
Handle IPv6 binding failures gracefully
Add a try-except block around the IPv6 socket creation and binding to handle cases where IPv6 is also unavailable, preventing potential unhandled exceptions that could crash the function.
py/selenium/webdriver/common/utils.py [34-44]
free_socket = None
try:
# IPv4
free_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
free_socket.bind(("127.0.0.1", 0))
except OSError:
if free_socket:
free_socket.close()
- # IPv6
- free_socket = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
- free_socket.bind(("::1", 0))
+ try:
+ # IPv6
+ free_socket = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
+ free_socket.bind(("::1", 0))
+ except OSError:
+ raise RuntimeError("Unable to bind to both IPv4 and IPv6")
Suggestion 6:
Ensure proper socket cleanup
The socket resource is not properly cleaned up if an exception occurs after the IPv6 socket creation or during listen/getsockname operations. Use a try-finally block to ensure the socket is always closed, preventing resource leaks.
py/selenium/webdriver/common/utils.py [45-47]
free_socket = None
try:
# IPv4
free_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
free_socket.bind(("127.0.0.1", 0))
except OSError:
if free_socket:
free_socket.close()
# IPv6
free_socket = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
free_socket.bind(("::1", 0))
-free_socket.listen(5)
-port: int = free_socket.getsockname()[1]
-free_socket.close()
+try:
+ free_socket.listen(5)
+ port: int = free_socket.getsockname()[1]
+finally:
+ free_socket.close()
+
Suggestion 7:
Prevent socket resource leak
The IPv4 socket should be closed if binding fails to prevent resource leaks. Currently, if IPv4 socket creation succeeds but binding fails, the socket remains open when the exception is caught.
py/selenium/webdriver/common/utils.py [34-44]
+free_socket = None
try:
# IPv4
free_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
free_socket.bind(("127.0.0.1", 0))
except OSError:
+ if free_socket:
+ free_socket.close()
# IPv6
free_socket = socket.socket(socket.AF_INET6, socket.SOCK_STREAM)
free_socket.bind(("::1", 0))
free_socket.listen(5)
port: int = free_socket.getsockname()[1]
free_socket.close()
Suggestion 8:
Add error handling
Add error handling to the kill method similar to what was added to terminate. This ensures consistent behavior when trying to kill a process that no longer exists.
rb/lib/selenium/webdriver/common/child_process.rb [129-131]
def kill(pid)
Process.kill(SIGKILL, pid)
+rescue Errno::ECHILD, Errno::ESRCH
+ # Process does not exist, nothing to kill
end
Suggestion 9:
Ensure proper resource cleanup
Ensure the driver is properly closed even if the test fails by using a try-finally block. Currently, if the test fails before reaching driver.quit(), the driver won't be properly cleaned up.
py/test/selenium/webdriver/remote/remote_connection_tests.py [38-53]
def test_remote_webdriver_with_http_timeout(firefox_options, webserver):
"""This test starts a remote webdriver with an http client timeout
set less than the implicit wait timeout, and verifies the http timeout
is triggered first when waiting for an element.
"""
http_timeout = 6
wait_timeout = 8
server_addr = f"http://{webserver.host}:{webserver.port}"
client_config = ClientConfig(remote_server_addr=server_addr, timeout=http_timeout)
assert client_config.timeout == http_timeout
driver = webdriver.Remote(options=firefox_options, client_config=client_config)
- driver.get(f"{server_addr}/simpleTest.html")
- driver.implicitly_wait(wait_timeout)
- with pytest.raises(ReadTimeoutError):
- driver.find_element(By.ID, "no_element_to_be_found")
- driver.quit()
+ try:
+ driver.get(f"{server_addr}/simpleTest.html")
+ driver.implicitly_wait(wait_timeout)
+ with pytest.raises(ReadTimeoutError):
+ driver.find_element(By.ID, "no_element_to_be_found")
+ finally:
+ driver.quit()
Suggestion 10:
Close socket to prevent leaks
The socket is not being closed after use, which can lead to resource leaks. Always close sockets after use, preferably using a context manager or explicitly calling close().
py/selenium/webdriver/remote/server.py [120-125]
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
host = self.host if self.host is not None else "localhost"
try:
sock.connect((host, self.port))
+ sock.close()
raise ConnectionError(f"Selenium server is already running, or something else is using port {self.port}")
except ConnectionRefusedError:
+ sock.close()
Suggestion 11:
Check process state before terminating
The stop() method should be more resilient by checking if the process is still running before attempting to terminate it. The current implementation could raise an exception if the process has already terminated.
py/selenium/webdriver/remote/server.py [134-142]
def stop(self):
"""Stop the server."""
if self.process is None:
raise RuntimeError("Selenium server isn't running")
else:
- self.process.terminate()
- self.process.wait()
+ if self.process.poll() is None: # Check if process is still running
+ self.process.terminate()
+ self.process.wait()
self.process = None
print("Selenium server has been terminated")
Suggestion 12:
Missing driver cleanup
The test is missing cleanup for driver2. If driver2 is successfully created, it should be quit in the finally block to properly release resources.
py/test/selenium/webdriver/chrome/chrome_service_tests.py [53-54]
finally:
driver1.quit()
+ if driver2:
+ driver2.quit()
Suggestion 13:
Handle undefined variable safely
The test is missing a reference to driver1 before quitting it in the finally block. Since driver1 is defined inside the try block, it might not exist if an exception occurs before its creation, causing a NameError.
py/test/selenium/webdriver/chrome/chrome_service_tests.py [54]
-driver1.quit()
+if 'driver1' in locals() and driver1:
+ driver1.quit()
Suggestion 14:
Fix DevTools connections closure
The current implementation of the quit method might not properly close all DevTools connections if @devtools is initialized but empty. Use each instead of map to ensure proper closure of all connections.
rb/lib/selenium/webdriver/common/driver.rb [187-192]
def quit
bridge.quit
ensure
@service_manager&.stop
- @devtools&.values&.map(&:close)
+ @devtools&.values&.each(&:close) if @devtools
end
Pattern 3: Fix string formatting and interpolation issues by using consistent approaches, proper escaping, and platform-appropriate separators. Replace verbose string.Format calls with string interpolation where appropriate.
Example code before:
var message = string.Format(CultureInfo.InvariantCulture, "Value: {0}", value);
var paths = pathString.Split(';');
Example code after:
var message = $"Value: {value}";
var paths = pathString.Split(Path.PathSeparator);
Relevant past accepted suggestions:
Suggestion 1:
Use string interpolation for cleaner code
Consider using string interpolation instead of string.Format for better readability and performance. The current approach is unnecessarily verbose for a simple string concatenation.
dotnet/src/webdriver/Chromium/ChromiumDriverService.cs [164]
-argsBuilder.Append(string.Format(CultureInfo.InvariantCulture, " --log-level={0}", this.LogLevel.ToString().ToUpperInvariant()));
+argsBuilder.Append($" --log-level={this.LogLevel.ToString().ToUpperInvariant()}");
Suggestion 2:
Use platform-appropriate path separator
The code assumes semicolon as the path separator, but this may not be correct on all platforms. On Unix-like systems, the path separator is typically a colon (:). Consider using Path.PathSeparator or detecting the platform-appropriate separator.
dotnet/src/webdriver/SeleniumManager.cs [105-111]
// Supporting .NET5+ applications deployed as self-contained applications (single file or AOT)
var nativeDllSearchDirectories = AppContext.GetData("NATIVE_DLL_SEARCH_DIRECTORIES")?.ToString();
if (nativeDllSearchDirectories is not null)
{
- probingPaths.AddRange(nativeDllSearchDirectories.Split(';').Select(path => Path.Combine(path, seleniumManagerFileName)));
+ probingPaths.AddRange(nativeDllSearchDirectories.Split(Path.PathSeparator).Select(path => Path.Combine(path, seleniumManagerFileName)));
}
Suggestion 3:
Add fallback for None reason
The response.reason might be None in some cases, which would result in "None" being displayed. Add a fallback to handle cases where the reason is not available.
py/selenium/webdriver/remote/remote_connection.py [443]
-return {"status": statuscode, "value": f"{response.reason}" if not data else data.strip()}
+return {"status": statuscode, "value": f"{response.reason or statuscode}" if not data else data.strip()}
Suggestion 4:
Fix inconsistent spacing
Remove the unnecessary spaces around the equal signs in the parameter assignments. This inconsistent spacing style differs from the rest of the codebase and violates PEP 8 style guidelines for Python.
py/selenium/webdriver/common/bidi/storage.py [90-92]
-name = str(data.get("name") or ""),
-domain = str(data.get("domain") or ""),
+name=str(data.get("name") or ""),
+domain=str(data.get("domain") or ""),
Suggestion 5:
Fix spacing in assignment
Remove the extra space before the equal sign. There are two spaces between the type annotation and the equal sign, which is inconsistent with Python style guidelines.
py/selenium/webdriver/common/bidi/storage.py [251]
-result: dict[str, Any] = {
+result: dict[str, Any] = {
Suggestion 6:
Fix grammatical errors
There's a grammatical error in the instructions about staging files after running black and isort. The phrase "should staged again" is incorrect and could confuse contributors.
py/docs/source/index.rst [178-180]
- `flake8` requires manual fixes
-- `black` will rewrite the violations automatically, however the files are unstaged and should staged again
-- `isort` will rewrite the violations automatically, however the files are unstaged and should staged again
+- `black` will rewrite the violations automatically, however the files are unstaged and should be staged again
+- `isort` will rewrite the violations automatically, however the files are unstaged and should be staged again
Suggestion 7:
Use explicit charset for bytes
Using getBytes() without specifying charset can lead to platform-dependent behavior and incorrect size calculations. Since GraphQL queries are typically UTF-8 encoded, explicitly specify the charset to ensure consistent byte length calculation across different platforms.
java/src/org/openqa/selenium/grid/graphql/GraphqlHandler.java [116-121]
// Query size validation with bypass for oversized queries
-if (query.getBytes().length > MAX_QUERY_SIZE_BYTES) {
+if (query.getBytes(StandardCharsets.UTF_8).length > MAX_QUERY_SIZE_BYTES) {
// Bypass cache for oversized queries to prevent cache pollution
return CompletableFuture.supplyAsync(
() -> computeFunction.apply(executionInput));
}
Suggestion 8:
Improve error message clarity
The error message should be more specific about the expected types. Currently it mentions "PartitionDescriptor" which is a parent class, but the check is specifically for BrowsingContextPartitionDescriptor or StorageKeyPartitionDescriptor.
javascript/node/selenium-webdriver/bidi/storage.js [56-61]
if (
partition !== undefined &&
!(partition instanceof BrowsingContextPartitionDescriptor || partition instanceof StorageKeyPartitionDescriptor)
) {
- throw new Error(`Params must be an instance of PartitionDescriptor. Received:'${partition}'`)
+ throw new Error(`Params must be an instance of BrowsingContextPartitionDescriptor or StorageKeyPartitionDescriptor. Received:'${partition}'`)
}
Suggestion 9:
Fix incorrect docstring description
The docstring for web_socket_url incorrectly states it's for accepting insecure certificates. It should describe WebSocket URL functionality instead.
py/selenium/webdriver/common/options.py [287-288]
web_socket_url = _BaseOptionsDescriptor("webSocketUrl")
-"""Gets and Set whether the session accepts insecure certificates.
+"""Gets and Sets WebSocket URL.
Suggestion 10:
Fix incorrect parameter type
The parameter and return type for web_socket_url are incorrectly documented as bool when they should be str based on the property name and its usage.
py/selenium/webdriver/common/options.py [421-439]
web_socket_url = _BaseOptionsDescriptor("webSocketUrl")
"""Gets and Sets WebSocket URL.
Usage:
------
- Get
- `self.web_socket_url`
- Set
- `self.web_socket_url` = `value`
Parameters:
-----------
-`value`: `bool`
+`value`: `str`
Returns:
--------
- Get
- - `bool`
+ - `str`
- Set
- `None`
"""
Suggestion 11:
Fix inconsistent docstring formatting
The indentation in the docstring is inconsistent. The "Example:" section has one less dash than the "Parameters:" section, which could cause issues with Sphinx documentation generation.
py/selenium/webdriver/remote/webdriver.py [814-824]
def set_page_load_timeout(self, time_to_wait: float) -> None:
"""Sets the amount of time to wait for a page load to complete before
throwing an error.
Parameters:
-----------
time_to_wait : float
- The amount of time to wait (in seconds)
Example:
- -------
+ --------
>>> driver.set_page_load_timeout(30)
"""
Pattern 4: Validate sequence and collection types properly by excluding strings from sequence checks (since strings are sequences in Python) and converting sequences to lists for consistent internal storage and mutability.
Example code before:
if not isinstance(value, Sequence):
raise TypeError("must be a sequence")
self._items = value
Example code after:
if isinstance(value, str) or not isinstance(value, Sequence):
raise TypeError("must be a sequence")
self._items = list(value)
Relevant past accepted suggestions:
Suggestion 1:
Fix string validation logic
The validation logic incorrectly rejects strings because strings are sequences in Python. The condition should use isinstance(value, str) first to exclude strings, then check if it's a sequence. This prevents valid non-string sequences from being rejected.
py/selenium/webdriver/chrome/service.py [61-65]
@service_args.setter
def service_args(self, value: Sequence[str]):
- if not isinstance(value, Sequence) or isinstance(value, str):
+ if isinstance(value, str) or not isinstance(value, Sequence):
raise TypeError("service_args must be a sequence")
self._service_args = list(value)
Suggestion 2:
Convert sequence to list consistently
The setter should convert the sequence to a list to maintain consistency with the internal storage format. The current implementation stores the sequence directly, which could lead to issues if a non-list sequence is provided.
py/selenium/webdriver/chromium/service.py [75-79]
@service_args.setter
def service_args(self, value: Sequence[str]):
if not isinstance(value, Sequence) or isinstance(value, str):
raise TypeError("service_args must be a sequence")
- self._service_args = value
+ self._service_args = list(value)
Suggestion 3:
Add string exclusion validation consistency
The setter validation is inconsistent with other service classes. It should also exclude strings from being accepted as valid sequences, since strings are sequences but not the intended type for service arguments.
py/selenium/webdriver/chrome/service.py [61-65]
@service_args.setter
def service_args(self, value: Sequence[str]):
- if not isinstance(value, Sequence):
+ if not isinstance(value, Sequence) or isinstance(value, str):
raise TypeError("service_args must be a sequence")
- self._service_args = value
+ self._service_args = list(value)
Suggestion 4:
Convert sequence to list consistently
The setter should convert the sequence to a list to maintain consistency with the internal storage format. The current implementation directly assigns the sequence, which could lead to type inconsistencies since _service_args is expected to be a list.
py/selenium/webdriver/chromium/service.py [75-79]
@service_args.setter
def service_args(self, value: Sequence[str]):
if not isinstance(value, Sequence) or isinstance(value, str):
raise TypeError("service_args must be a sequence")
- self._service_args = value
+ self._service_args = list(value)
Suggestion 5:
Convert sequence to list assignment
Convert the sequence to a list before assignment to maintain consistency with the internal storage format and avoid potential issues with immutable sequences
py/selenium/webdriver/edge/service.py [64-68]
@service_args.setter
def service_args(self, value: Sequence[str]):
if not isinstance(value, Sequence) or isinstance(value, str):
raise TypeError("service_args must be a sequence")
- self._service_args = value
+ self._service_args = list(value)
Suggestion 6:
Add string exclusion validation consistency
The setter validation is inconsistent with other service classes. It should also exclude strings from being accepted as valid sequences, since strings are sequences but not the intended type.
py/selenium/webdriver/chrome/service.py [61-65]
@service_args.setter
def service_args(self, value: Sequence[str]):
- if not isinstance(value, Sequence):
+ if not isinstance(value, Sequence) or isinstance(value, str):
raise TypeError("service_args must be a sequence")
- self._service_args = value
+ self._service_args = list(value)
Suggestion 7:
Improve validation and conversion consistency
The setter validation should exclude strings and convert the sequence to a list for consistency with other service classes and internal storage format.
py/selenium/webdriver/edge/service.py [64-68]
@service_args.setter
def service_args(self, value: Sequence[str]):
- if not isinstance(value, Sequence):
+ if not isinstance(value, Sequence) or isinstance(value, str):
raise TypeError("service_args must be a sequence")
- self._service_args = value
+ self._service_args = list(value)
Suggestion 8:
Convert sequence to list
Convert the value to a list before assignment to ensure the internal storage is mutable and consistent with the initialization pattern used elsewhere in the codebase.
py/selenium/webdriver/chromium/service.py [77-79]
if not isinstance(value, Sequence) or isinstance(value, str):
raise TypeError("service_args must be a sequence")
-self._service_args = value
+self._service_args = list(value)
Suggestion 9:
Ensure service args mutability
Convert the input sequence to a list to ensure mutability for operations like append() used elsewhere in the code. This prevents potential issues when immutable sequences are passed.
py/selenium/webdriver/chromium/service.py [48]
-self._service_args = service_args or []
+self._service_args = list(service_args or [])
Suggestion 10:
Prevent strings as sequence arguments
The type check should exclude strings since they are sequences but shouldn't be treated as argument lists. Add a check to prevent strings from being accepted as valid sequences.
py/selenium/webdriver/chromium/service.py [75-79]
@service_args.setter
def service_args(self, value: Sequence[str]):
- if not isinstance(value, Sequence):
+ if not isinstance(value, Sequence) or isinstance(value, str):
raise TypeError("service_args must be a sequence")
self._service_args = value
Suggestion 11:
Fix inconsistent attribute assignment
The service_args assignment should use the private attribute _service_args to be consistent with the property implementation. This ensures the getter/setter pattern works correctly.
py/selenium/webdriver/wpewebkit/service.py [40-49]
def __init__(
self,
executable_path: str = DEFAULT_EXECUTABLE_PATH,
port: int = 0,
log_output: Optional[str] = None,
service_args: Optional[Sequence[str]] = None,
env: Optional[Mapping[str, str]] = None,
**kwargs,
):
- self.service_args = service_args or []
+ self._service_args = service_args or []
Pattern 5: Fix syntax errors, typos, and naming inconsistencies in code, comments, and documentation to maintain code quality and prevent confusion for developers and users.
Example code before:
// This is the preview of the system
def test_function_with_typo_paraeter():
return "br formatted"
Example code after:
// This is the purview of the system
def test_function_with_typo_parameter():
return "be formatted"
Relevant past accepted suggestions:
Suggestion 1:
Fix incorrect word usage
The word "preview" should be "purview" in this context. "Purview" means the scope or range of authority, while "preview" means a preliminary view or showing.
dotnet/src/webdriver/PinnedScript.cs [36-40]
/// <remarks>
/// This constructor is explicitly internal. Creation of pinned script objects
-/// is strictly the preview of Selenium, and should not be required by external
+/// is strictly the purview of Selenium, and should not be required by external
/// libraries.
/// </remarks>
Suggestion 2:
Fix typo in JavaDoc comment
Fix the typo "br" to "be" in the JavaDoc comment. The word "br" should be "be" to make the sentence grammatically correct.
java/src/org/openqa/selenium/json/JsonOutput.java [267]
-* Specify whether the serialized JSON object should br formatted with line breaks and indentation
+* Specify whether the serialized JSON object should be formatted with line breaks and indentation
Suggestion 3:
Fix incorrect macOS key mapping
The key mappings appear incorrect for macOS. The Options key should map to Alt/Option functionality, not right_shift, and the Function key has its own distinct behavior that shouldn't be aliased to right_control.
rb/lib/selenium/webdriver/common/keys.rb [98-99]
-options: "\ue050", # macOS Options key, same as right_shift
+options: "\ue052", # macOS Options key, same as right_alt
function: "\ue051", # macOS Function key, same as right_control
Suggestion 4:
Fix incorrect event subscription name
The OnHistoryUpdatedAsync methods are subscribing to the wrong event name. They should subscribe to "browsingContext.historyUpdated" instead of "browsingContext.fragmentNavigated" to match their intended functionality.
dotnet/src/webdriver/BiDi/BrowsingContext/BrowsingContextModule.cs [137-145]
public async Task<Subscription> OnHistoryUpdatedAsync(Func<HistoryUpdatedEventArgs, Task> handler, BrowsingContextsSubscriptionOptions? options = null)
{
- return await Broker.SubscribeAsync("browsingContext.fragmentNavigated", handler, options).ConfigureAwait(false);
+ return await Broker.SubscribeAsync("browsingContext.historyUpdated", handler, options).ConfigureAwait(false);
}
public async Task<Subscription> OnHistoryUpdatedAsync(Action<HistoryUpdatedEventArgs> handler, BrowsingContextsSubscriptionOptions? options = null)
{
- return await Broker.SubscribeAsync("browsingContext.fragmentNavigated", handler, options).ConfigureAwait(false);
+ return await Broker.SubscribeAsync("browsingContext.historyUpdated", handler, options).ConfigureAwait(false);
}
Suggestion 5:
Fix incomplete variable assignment
The else branch assigns None to nothing, which is a no-op. This should assign None to remote_server_addr or handle the case where command_executor doesn't have the expected attributes.
py/selenium/webdriver/remote/webdriver.py [126-129]
if hasattr(command_executor, "client_config") and command_executor.client_config:
remote_server_addr = command_executor.client_config.remote_server_addr
else:
- None
+ remote_server_addr = command_executor
Suggestion 6:
Fix indentation error
Fix the indentation error in line 142 where a tab character is used instead of spaces, which will cause a syntax error.
py/selenium/webdriver/common/bidi/browser.py [142-148]
+width = data["width"]
+if not isinstance(width, int) or width < 0:
+ raise ValueError(f"width must be a non-negative integer, got {width}")
+height = data["height"]
+if not isinstance(height, int) or height < 0:
+ raise ValueError(f"height must be a non-negative integer, got {height}")
Suggestion 7:
Fix indentation error
Fix the indentation error on line 142. The line uses tabs instead of spaces, which is inconsistent with the rest of the code and will cause a Python indentation error.
py/selenium/webdriver/common/bidi/browser.py [142]
+width = data["width"]
+if not isinstance(width, int) or width < 0:
+ raise ValueError(f"width must be a non-negative integer, got {width}")
-
Suggestion 8:
Fix documentation example
Fix the syntax error in the example code where there's an extra closing parenthesis. This will prevent confusion for users following the documentation.
py/selenium/webdriver/remote/webdriver.py [1348-1361]
@property
def webextension(self):
"""Returns a webextension module object for BiDi webextension commands.
Returns:
--------
WebExtension: an object containing access to BiDi webextension commands.
Examples:
---------
>>> extension_path = "/path/to/extension"
- >>> extension_result = driver.webextension.install(path=extension_path)))
+ >>> extension_result = driver.webextension.install(path=extension_path)
>>> driver.webextension.uninstall(extension_result)
"""
Suggestion 9:
Fix unbalanced parentheses
The parentheses in this example are not properly balanced. The closing parenthesis for the method call is placed on a new line but is not aligned with the opening parenthesis, which can lead to syntax errors or confusion.
py/selenium/webdriver/support/expected_conditions.py [391-393]
->>> is_text_in_element = WebDriverWait(driver, 10).until(EC.text_to_be_present_in_element(
- (By.CLASS_NAME, "foo"), "bar")
- )
+>>> is_text_in_element = WebDriverWait(driver, 10).until(
+... EC.text_to_be_present_in_element((By.CLASS_NAME, "foo"), "bar")
+... )
Suggestion 10:
Fix duplicate variable assignment
There's a duplicate variable assignment with options = options =. This creates a redundant assignment that doesn't cause functional issues but is unnecessary and confusing. Remove the duplication.
-options = options = getattr(webdriver, f"{driver_class}Options")()
+options = getattr(webdriver, f"{driver_class}Options")()
Suggestion 11:
Fix duplicate variable assignment
There's a duplicate variable assignment with options = options =. This creates a redundant assignment that doesn't cause functional issues but is unnecessary and confusing. Remove the duplication.
-options = options = getattr(webdriver, f"{driver_class}Options")()
+options = getattr(webdriver, f"{driver_class}Options")()
Suggestion 12:
Fix inconsistent log message
The log message doesn't match the test expectation. The test expects a message containing "No valid process exit status" but the actual message uses "Invalid process exit status". Update the log message to match the test expectation.
rb/lib/selenium/webdriver/common/selenium_manager.rb [108-118]
def validate_command_result(command, status, result, stderr)
if status.nil? || status.exitstatus.nil?
- WebDriver.logger.info("Invalid process exit status for: #{command}. Assuming success if result is present.",
+ WebDriver.logger.info("No valid process exit status for: #{command}. Assuming success if result is present.",
id: :selenium_manager)
end
return unless status&.exitstatus&.positive? || result.nil?
raise Error::WebDriverError,
"Unsuccessful command executed: #{command} - Code #{status&.exitstatus}\n#{result}\n#{stderr}"
end
Suggestion 13:
Fix typo in function name
Fix the typo in the test function name. "paraeter" should be "parameter".
py/test/selenium/webdriver/remote/remote_tests.py [25]
-def test_remote_webdriver_requires_options_paraeter():
+def test_remote_webdriver_requires_options_parameter():
Suggestion 14:
Rename test function
The test function name test_remote_webdriver_requires_options_kwarg() implies that options is a keyword-only argument, but in the implementation it's a regular parameter. Consider renaming the test function to better reflect what's being tested.
py/test/selenium/webdriver/remote/remote_tests.py [25-32]
-def test_remote_webdriver_requires_options_kwarg():
+def test_remote_webdriver_requires_options_parameter():
msg = "missing 1 required keyword-only argument: 'options' (instance of driver `options.Options` class)"
with pytest.raises(TypeError, match=re.escape(msg)):
webdriver.Remote()
with pytest.raises(TypeError, match=re.escape(msg)):
webdriver.Remote(None)
with pytest.raises(TypeError, match=re.escape(msg)):
webdriver.Remote(options=None)
Suggestion 15:
Remove duplicate property declaration
The web_socket_url property is duplicated in the BaseOptions class. There are two identical property declarations at lines 287 and 421, which could cause confusion or unexpected behavior.
py/selenium/webdriver/common/options.py [421-441]
-web_socket_url = _BaseOptionsDescriptor("webSocketUrl")
-"""Gets and Sets WebSocket URL.
+# Remove the duplicate declaration, keeping only one instance of web_socket_url
-Usage:
-------
-- Get
- - `self.web_socket_url`
-- Set
- - `self.web_socket_url` = `value`
-
-Parameters:
------------
-`value`: `bool`
-
-Returns:
---------
-- Get
- - `bool`
-- Set
- - `None`
-"""
-
Suggestion 16:
Fix boolean assertion logic
The JavaScript assertion for Boolean values is incorrect. The typeof operator returns the string "boolean" for boolean values, and you're comparing it directly to true/false. You should either remove the typeof or change the assertion to check the value directly.
dotnet/test/common/BiDi/Script/CallFunctionParameterTest.cs [275-282]
-//yield return new TestCaseData(new LocalValue.Boolean(true), new RemoteValue.Boolean(true), "typeof arg === true")
+//yield return new TestCaseData(new LocalValue.Boolean(true), new RemoteValue.Boolean(true), "arg === true")
//{
// TestName = nameof(CanCallFunctionAndRoundtrip_Five) + "(true)",
//};
-//yield return new TestCaseData(new LocalValue.Boolean(false), new RemoteValue.Boolean(false), "typeof arg === false")
+//yield return new TestCaseData(new LocalValue.Boolean(false), new RemoteValue.Boolean(false), "arg === false")
//{
// TestName = nameof(CanCallFunctionAndRoundtrip_Five) + "(false)",
//};
Suggestion 17:
Add Async suffix
The method should be named with the "Async" suffix to follow the async method naming convention, as it returns a Task and calls an async method.
dotnet/src/webdriver/BiDi/Modules/BrowsingContext/BrowsingContextInputModule.cs [38-41]
-public Task SetFiles(Script.ISharedReference element, IEnumerable<string> files, SetFilesOptions? options = null)
+public Task SetFilesAsync(Script.ISharedReference element, IEnumerable<string> files, SetFilesOptions? options = null)
{
return inputModule.SetFilesAsync(context, element, files, options);
}
[Auto-generated best practices - 2025-07-30]
This wiki is not where you want to be! Visit the Wiki Home for more useful links
Getting Involved
Triaging Issues
Releasing Selenium
Ruby Development
Python Bindings
Ruby Bindings
WebDriverJs
This content is being evaluated for where it belongs
Architectural Overview
Automation Atoms
HtmlUnitDriver
Lift Style API
LoadableComponent
Logging
PageFactory
RemoteWebDriver
Xpath In WebDriver
Moved to Official Documentation
Bot Style Tests
Buck
Continuous Integration
Crazy Fun Build
Design Patterns
Desired Capabilities
Developer Tips
Domain Driven Design
Firefox Driver
Firefox Driver Internals
Focus Stealing On Linux
Frequently Asked Questions
Google Summer Of Code
Grid Platforms
History
Internet Explorer Driver
InternetExplorerDriver Internals
Next Steps
PageObjects
RemoteWebDriverServer
Roadmap
Scaling WebDriver
SeIDE Release Notes
Selenium Emulation
Selenium Grid 4
Selenium Help
Shipping Selenium 3
The Team
TLC Meetings
Untrusted SSL Certificates
WebDriver For Mobile Browsers
Writing New Drivers