Skip to content

.pr_agent_auto_best_practices

root edited this page Apr 30, 2025 · 6 revisions

Pattern 1: Add null checks for parameters and properties before using them to prevent NullReferenceExceptions. Validate input parameters at the beginning of methods and handle null values appropriately with clear error messages.

Example code before:

public void ProcessData(string input) {
    var result = input.ToUpper();
    // Use result...
}

Example code after:

public void ProcessData(string input) {
    ArgumentNullException.ThrowIfNull(input, nameof(input));
    var result = input.ToUpper();
    // Use result...
}
Relevant past accepted suggestions:
Suggestion 1:

Prevent removing default context

Add validation to prevent removing the "default" user context. The docstring mentions that an exception will be raised if the user context ID is "default", but there's no actual validation in the code to prevent this operation.

py/selenium/webdriver/common/bidi/browser.py [168-180]

 def remove_user_context(self, user_context_id: str) -> None:
     """Removes a user context.
 
     Parameters:
     -----------
         user_context_id: The ID of the user context to remove.
 
     Raises:
     ------
         Exception: If the user context ID is "default" or does not exist.
     """
+    if user_context_id == "default":
+        raise Exception("Cannot remove the default user context")
+        
     params = {"userContext": user_context_id}
     self.conn.execute(command_builder("browser.removeUserContext", params))

Suggestion 2:

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 3:

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);

Suggestion 4:

Add null check for handler

Add null check for the returned HttpClientHandler from CreateHttpClientHandler() before using it to avoid potential NullReferenceException

dotnet/src/webdriver/Remote/HttpCommandExecutor.cs [248-252]

 protected virtual HttpClient CreateHttpClient()
 {
     var httpClientHandler = CreateHttpClientHandler();
+    if (httpClientHandler == null)
+    {
+        throw new InvalidOperationException("CreateHttpClientHandler() returned null");
+    }
 
     HttpMessageHandler handler = httpClientHandler;

Suggestion 5:

Add null validation check for required class field to prevent potential NullReferenceException

The CreateHttpClientHandler() method uses this.remoteServerUri without validating that it's not null. Since this is a required field for the class functionality, add a null check at the start of the method to fail fast with a clear error message.

dotnet/src/webdriver/Remote/HttpCommandExecutor.cs [229-233]

 protected virtual HttpClientHandler CreateHttpClientHandler()
 {
+    ArgumentNullException.ThrowIfNull(this.remoteServerUri, nameof(remoteServerUri));
     HttpClientHandler httpClientHandler = new HttpClientHandler();
     string userInfo = this.remoteServerUri.UserInfo;
     if (!string.IsNullOrEmpty(userInfo) && userInfo.Contains(":"))

Suggestion 6:

Add parameter validation

Add null checks for the subscription ID and event handler parameters to prevent potential NullReferenceException when unsubscribing.

dotnet/src/webdriver/BiDi/Communication/Broker.cs [274-281]

 public async Task UnsubscribeAsync(Modules.Session.Subscription subscription, EventHandler eventHandler)
 {
+    ArgumentNullException.ThrowIfNull(subscription);
+    ArgumentNullException.ThrowIfNull(eventHandler);
+    
     var eventHandlers = _eventHandlers[eventHandler.EventName];
     eventHandlers.Remove(eventHandler);
     await _bidi.SessionModule.UnsubscribeAsync([subscription]).ConfigureAwait(false);
 }

Suggestion 7:

Add null check for response value

Add null check for response.Value in GetContext() method before attempting ToString() conversion to avoid potential NullReferenceException.

dotnet/src/webdriver/Firefox/FirefoxDriver.cs [263-266]

 Response commandResponse = this.Execute(GetContextCommand, null);
 
-if (commandResponse.Value is not string response
+if (commandResponse.Value is null
+    || commandResponse.Value is not string response
     || !Enum.TryParse(response, ignoreCase: true, out FirefoxCommandContext output))

Suggestion 8:

Prevent null reference exception

Add null check for binaryPaths.BrowserPath before validating file existence to prevent NullReferenceException. The browser path might be null in some cases.

dotnet/src/webdriver/DriverFinder.cs [119-122]

-if (!File.Exists(binaryPaths.BrowserPath))
+if (!string.IsNullOrEmpty(binaryPaths.BrowserPath) && !File.Exists(binaryPaths.BrowserPath))
 {
     throw new NoSuchDriverException($"The browser path is not a valid file: {binaryPaths.BrowserPath}");
 }

Suggestion 9:

Handle null browser path safely

Add null check for path before accessing it in GetBrowserPath() to prevent potential NullReferenceException when accessing BrowserPath property.

dotnet/src/webdriver/DriverFinder.cs [56-59]

 public string GetBrowserPath()
 {
-    return BinaryPaths().BrowserPath;
+    var paths = BinaryPaths();
+    return paths.BrowserPath ?? string.Empty;
 }

Suggestion 10:

Handle null response values

Add null check for commandResponse.Value before calling ToString() since the response value could be null, which would cause a NullReferenceException

dotnet/src/webdriver/WebElement.cs [100-102]

 Response commandResponse = this.Execute(DriverCommand.GetElementText, parameters);
-return commandResponse.Value.ToString();
+return commandResponse.Value?.ToString() ?? string.Empty;

Suggestion 11:

Add null check for path

Add null check for Path.GetDirectoryName() result since it can return null for invalid paths. The current forced null-forgiving operator (!) could lead to NullReferenceException.

dotnet/src/webdriver/Firefox/FirefoxDriverService.cs [203]

-driverPath = Path.GetDirectoryName(driverPath)!;
+var dirPath = Path.GetDirectoryName(driverPath);
+if (dirPath == null) throw new ArgumentException("Invalid driver path provided", nameof(driverPath));
+driverPath = dirPath;

Suggestion 12:

Add null parameter validation

Add null check for webDriver parameter to prevent NullReferenceException when calling the extension method with null

dotnet/src/webdriver/BiDi/WebDriver.Extensions.cs [29-31]

 public static async Task<BiDi> AsBiDiAsync(this IWebDriver webDriver)
 {
+    ArgumentNullException.ThrowIfNull(webDriver);
     var webSocketUrl = ((IHasCapabilities)webDriver).Capabilities.GetCapability("webSocketUrl");

Suggestion 13:

Add proper validation for nullable values before using them to prevent potential runtime errors

The code uses null-forgiving operator (!) on webSocketUrl.ToString() which could lead to runtime errors if webSocketUrl is null. Instead, validate the value before using it and provide a clear error message.

dotnet/src/webdriver/BiDi/WebDriver.Extensions.cs [33-35]

-if (webSocketUrl is null) throw new BiDiException("The driver is not compatible with bidirectional protocol or \"webSocketUrl\" not enabled in driver options.");
-var bidi = await BiDi.ConnectAsync(webSocketUrl.ToString()!).ConfigureAwait(false);
+if (webSocketUrl is null)
+    throw new BiDiException("The driver is not compatible with bidirectional protocol or \"webSocketUrl\" not enabled in driver options.");
 
+var webSocketUrlStr = webSocketUrl.ToString();
+if (string.IsNullOrEmpty(webSocketUrlStr))
+    throw new BiDiException("Invalid empty webSocketUrl value");
+    
+var bidi = await BiDi.ConnectAsync(webSocketUrlStr).ConfigureAwait(false);
+

Suggestion 14:

Add parameter validation to prevent null reference exceptions

Add null check for value parameter in FromJson method to prevent potential NullReferenceException when deserializing JSON.

dotnet/src/webdriver/Response.cs [74-76]

 public static Response FromJson(string value)
 {
+    if (string.IsNullOrEmpty(value))
+    {
+        throw new ArgumentNullException(nameof(value));
+    }
     Dictionary<string, object> rawResponse = JsonSerializer.Deserialize<Dictionary<string, object>>(value, s_jsonSerializerOptions)

Suggestion 15:

Add null check for required parameter to prevent runtime errors

Add null check for target parameter in ConvertElement() since it's marked as nullable but the method assumes it's non-null.

dotnet/src/webdriver/Interactions/PointerInputDevice.cs [584-588]

 private Dictionary<string, object> ConvertElement()
 {
+    if (this.target == null)
+    {
+        throw new ArgumentNullException(nameof(target));
+    }
     if (this.target is IWebDriverObjectReference element)
     {
         return element.ToDictionary();
     }

Suggestion 16:

Add parameter validation to prevent null reference exceptions

Add null check for key parameter in SetPreferenceValue method to prevent potential issues with null keys.

dotnet/src/webdriver/Firefox/Preferences.cs [166-168]

 private void SetPreferenceValue(string key, JsonNode? value)
 {
+    if (key == null)
+        throw new ArgumentNullException(nameof(key));
     if (!this.IsSettablePreference(key))

Pattern 2: Use try-finally blocks to ensure proper resource cleanup, especially for driver instances and other disposable resources, even when exceptions occur during test execution.

Example code before:

public void TestMethod() {
    var driver = new WebDriver();
    driver.Navigate().GoToUrl("https://example.com");
    driver.FindElement(By.Id("element")).Click();
    driver.Quit();
}

Example code after:

public void TestMethod() {
    var driver = new WebDriver();
    try {
        driver.Navigate().GoToUrl("https://example.com");
        driver.FindElement(By.Id("element")).Click();
    } finally {
        driver.Quit();
    }
}
Relevant past accepted suggestions:
Suggestion 1:

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 2:

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 3:

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 4:

Properly dispose of HTTP client resources to prevent memory leaks

Dispose of the HttpClient instance in the Dispose method to prevent resource leaks. The current implementation might leave the HttpClient hanging.

dotnet/src/webdriver/Remote/HttpCommandExecutor.cs [52]

 private HttpClient? client;
 
+public void Dispose()
+{
+    if (!isDisposed)
+    {
+        client?.Dispose();
+        client = null;
+        isDisposed = true;
+    }
+}
+

Pattern 3: Check dictionary key existence before accessing values to prevent KeyNotFoundException. Use TryGetValue or ContainsKey methods to safely access dictionary entries.

Example code before:

var value = dictionary[key];
ProcessValue(value);

Example code after:

if (dictionary.TryGetValue(key, out var value)) {
    ProcessValue(value);
}
Relevant past accepted suggestions:
Suggestion 1:

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 2:

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 3:

Validate JSON property existence

Add null check for the 'clientWindows' property existence in JSON to prevent potential JsonException

dotnet/src/webdriver/BiDi/Communication/Json/Converters/Enumerable/GetClientWindowsResultConverter.cs [35]

-var clientWindows = doc.RootElement.GetProperty("clientWindows").Deserialize<IReadOnlyList<ClientWindowInfo>>(options);
+if (!doc.RootElement.TryGetProperty("clientWindows", out JsonElement clientWindowsElement))
+    throw new JsonException("Missing required 'clientWindows' property");
+var clientWindows = clientWindowsElement.Deserialize<IReadOnlyList<ClientWindowInfo>>(options);

Pattern 4: Fix inconsistent error messages and validation logic. Ensure error messages are clear, accurate, and provide specific information about the error condition and expected values.

Example code before:

if (value < 0) {
    throw new ArgumentException("Invalid value");
}

Example code after:

if (value < 0) {
    throw new ArgumentException($"Value must be non-negative. Received: {value}");
}
Relevant past accepted suggestions:
Suggestion 1:

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 2:

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)
     """

Suggestion 3:

Prevent potential null reference

The Title property should check if commandResponse is null before using the null-coalescing operator on its Value property to avoid potential NullReferenceException.

dotnet/src/webdriver/WebDriver.cs [123]

-object returnedTitle = commandResponse?.Value ?? string.Empty;
+object returnedTitle = commandResponse == null ? string.Empty : commandResponse.Value ?? string.Empty;

Suggestion 4:

Enhance error messages with actual values for better debugging experience

Include the actual value in the exception message to help with debugging when an invalid cookie name is provided.

dotnet/src/webdriver/CookieJar.cs [82]

-throw new ArgumentException("Cookie name cannot be empty", nameof(name));
+throw new ArgumentException($"Cookie name cannot be empty. Provided value: '{name}'", nameof(name));

Suggestion 5:

Provide accurate error messages that reflect the actual system locale instead of assuming Arabic

The error message incorrectly assumes the system language is Arabic when it's any non-English locale. Update the message to be more accurate and include the actual locale in the error message.

java/src/org/openqa/selenium/chrome/ChromeDriverService.java [289]

-throw new NumberFormatException("Couldn't format the port numbers because the System Language is arabic: \"" + String.format("--port=%d", getPort()) +
+throw new NumberFormatException("Couldn't format the port numbers due to non-English system locale '" + Locale.getDefault(Locale.Category.FORMAT) + "': \"" + String.format("--port=%d", getPort()) +

Pattern 5: Initialize collections and properties with safe default values instead of null to prevent NullReferenceExceptions. Use empty collections or appropriate default values for properties.

Example code before:

public class RequestHandler {
    public List<string> Headers { get; set; } = null!;
    
    public void AddHeader(string name, string value) {
        Headers.Add($"{name}: {value}");
    }
}

Example code after:

public class RequestHandler {
    public List<string> Headers { get; set; } = new List<string>();
    
    public void AddHeader(string name, string value) {
        Headers.Add($"{name}: {value}");
    }
}
Relevant past accepted suggestions:
Suggestion 1:

Initialize collection to prevent nulls

Initialize the Headers dictionary in the parameterless constructor to prevent NullReferenceException when adding headers.

dotnet/src/webdriver/HttpRequestData.cs [34-39]

 public HttpRequestData()
 {
     this.Method = null!;
     this.Url = null!;
-    this.Headers = null!;
+    this.Headers = new Dictionary<string, string>();
 }

Suggestion 2:

Use meaningful defaults over nulls

Avoid using null-forgiving operator (!) for required properties. Instead, initialize with meaningful default values.

dotnet/src/webdriver/HttpRequestData.cs [34-39]

 public HttpRequestData()
 {
-    this.Method = null!;
-    this.Url = null!;
-    this.Headers = null!;
+    this.Method = "GET";
+    this.Url = string.Empty;
+    this.Headers = new Dictionary<string, string>();
 }

Suggestion 3:

Avoid null reference runtime exceptions

Initialize RequestMatcher in the constructor instead of using null! to avoid potential null reference exceptions at runtime.

dotnet/src/webdriver/NetworkRequestHandler.cs [35]

-public Func<HttpRequestData, bool> RequestMatcher { get; set; } = null!;
+public Func<HttpRequestData, bool> RequestMatcher { get; set; } = _ => false;

Suggestion 4:

Provide safe default function implementations

Initialize ResponseMatcher and ResponseTransformer in the constructor with safe default implementations instead of using null! to avoid potential null reference exceptions.

dotnet/src/webdriver/NetworkResponseHandler.cs [35-42]

-public Func<HttpResponseData, bool> ResponseMatcher { get; set; } = null!;
-public Func<HttpResponseData, HttpResponseData> ResponseTransformer { get; set; } = null!;
+public Func<HttpResponseData, bool> ResponseMatcher { get; set; } = _ => false;
+public Func<HttpResponseData, HttpResponseData> ResponseTransformer { get; set; } = response => response;

Suggestion 5:

Add safe default function implementation

Initialize UriMatcher with a safe default implementation instead of using null! to avoid potential null reference exceptions.

dotnet/src/webdriver/NetworkAuthenticationHandler.cs [35]

-public Func<Uri, bool> UriMatcher { get; set; } = null!;
+public Func<Uri, bool> UriMatcher { get; set; } = _ => false;

Suggestion 6:

Add null safety checks and proper dictionary access to prevent potential runtime exceptions

The IsEnabled method could throw a NullReferenceException if _loggers is null or if the logger's issuer type is not found in the dictionary. Add null checks and fallback logic.

dotnet/src/webdriver/Internal/Logging/LogContext.cs [104]

-return Handlers != null && level >= _level && level >= _loggers?[logger.Issuer].Level;
+return Handlers != null && level >= _level && (_loggers?.TryGetValue(logger.Issuer, out var loggerEntry) != true || level >= loggerEntry.Level);

Suggestion 7:

Add null checks during dictionary initialization to prevent potential null reference exceptions

The logger initialization in constructor could fail if any of the source loggers has a null Issuer. Add validation to handle this case.

dotnet/src/webdriver/Internal/Logging/LogContext.cs [51]

-_loggers = new ConcurrentDictionary<Type, ILogger>(loggers.Select(l => new KeyValuePair<Type, ILogger>(l.Key, new Logger(l.Value.Issuer, level))));
+_loggers = new ConcurrentDictionary<Type, ILogger>(loggers.Where(l => l.Value?.Issuer != null).Select(l => new KeyValuePair<Type, ILogger>(l.Key, new Logger(l.Value.Issuer, level))));

[Auto-generated best practices - 2025-04-30]

Clone this wiki locally