Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[dotnet] Align webdriver errors with spec #14936

Merged
merged 17 commits into from
Dec 26, 2024

Conversation

RenderMichael
Copy link
Contributor

@RenderMichael RenderMichael commented Dec 23, 2024

User description

Thanks for contributing to Selenium!
A PR well described will help maintainers to quickly review and merge it

Before submitting your PR, please check our contributing guidelines.
Avoid large PRs, help reviewers by making them as simple and short as possible.

Description

Obsoletes out-of-spec result status UnhandledError. Replace usage with unknown error and unsupported operation.

Introduced custom exception types for some now-handled error codes. Only change visible to users is a WebDriverException will be replaced with a more specific exception type (that derives from WebDriverException).

Motivation and Context

Broken off from #14892. This removes a webdriver result option for something which does not exist in the spec.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)

Checklist

  • I have read the contributing document.
  • My change requires a change to the documentation.
  • I have updated the documentation accordingly.
  • I have added tests to cover my changes.
  • All new and existing tests passed.

PR Type

Enhancement


Description

This PR implements W3C WebDriver specification compliance changes for error handling:

  • Removes non-standard UnhandledError status and replaces it with W3C-compliant UnknownError and UnsupportedOperation statuses
  • Adds new exception classes: UnknownErrorException and UnsupportedOperationException
  • Updates error mappings and handling across the .NET WebDriver implementation
  • Improves error specificity by replacing generic WebDriverException with more specific exception types
  • All changes maintain backward compatibility as new exceptions derive from WebDriverException

Changes walkthrough 📝

Relevant files
Enhancement
HttpCommandExecutor.cs
Update error status in HTTP command executor                         

dotnet/src/webdriver/Remote/HttpCommandExecutor.cs

  • Replaced UnhandledError with UnknownError in error response handling
  • +1/-1     
    UnknownErrorException.cs
    Add UnknownErrorException class implementation                     

    dotnet/src/webdriver/UnknownErrorException.cs

  • Added new exception class for unknown errors in remote end processing
  • Implements standard exception constructors with message and inner
    exception support
  • +51/-0   
    UnsupportedOperationException.cs
    Add UnsupportedOperationException class implementation     

    dotnet/src/webdriver/UnsupportedOperationException.cs

  • Added new exception class for unsupported operations
  • Implements standard exception constructors with message and inner
    exception support
  • +50/-0   
    WebDriver.cs
    Update WebDriver error handling implementation                     

    dotnet/src/webdriver/WebDriver.cs

  • Replaced UnhandledError with UnknownError in error handling
  • Added handling for UnknownError and UnsupportedOperation exceptions
  • Removed obsolete UnhandledError case
  • +7/-4     
    WebDriverError.cs
    Update WebDriver error mappings                                                   

    dotnet/src/webdriver/WebDriverError.cs

  • Updated error mappings to use UnknownError and UnsupportedOperation
    instead of UnhandledError
  • +2/-2     
    WebDriverResult.cs
    Update WebDriverResult enum definitions                                   

    dotnet/src/webdriver/WebDriverResult.cs

  • Replaced UnhandledError enum value with UnknownError
  • Added new UnsupportedOperation enum value
  • Updated documentation comments
  • +7/-2     

    💡 PR-Agent usage: Comment /help "your question" on any pull request to receive relevant information

    Copy link
    Contributor

    PR Reviewer Guide 🔍

    Here are some key observations to aid the review process:

    ⏱️ Estimated effort to review: 2 🔵🔵⚪⚪⚪
    🧪 No relevant tests
    🔒 No security concerns identified
    ⚡ Recommended focus areas for review

    Error Handling

    Verify that all error cases are properly mapped to the new UnknownError and UnsupportedOperation exceptions and no error conditions are missed in the switch statement.

                                throw new ElementNotVisibleException(errorMessage);
    
                            case WebDriverResult.InvalidElementState:
                            case WebDriverResult.ElementNotSelectable:
                                throw new InvalidElementStateException(errorMessage);
    
                            case WebDriverResult.NoSuchDocument:
                                throw new NoSuchElementException(errorMessage);
    
                            case WebDriverResult.Timeout:
                                throw new WebDriverTimeoutException(errorMessage);
    
                            case WebDriverResult.NoSuchWindow:
                                throw new NoSuchWindowException(errorMessage);
    
                            case WebDriverResult.InvalidCookieDomain:
                                throw new InvalidCookieDomainException(errorMessage);
    
                            case WebDriverResult.UnableToSetCookie:
                                throw new UnableToSetCookieException(errorMessage);
    
                            case WebDriverResult.AsyncScriptTimeout:
                                throw new WebDriverTimeoutException(errorMessage);
    
                            case WebDriverResult.UnexpectedAlertOpen:
                                // TODO(JimEvans): Handle the case where the unexpected alert setting
                                // has been set to "ignore", so there is still a valid alert to be
                                // handled.
                                string alertText = string.Empty;
                                if (errorAsDictionary.ContainsKey("alert"))
                                {
                                    Dictionary<string, object> alertDescription = errorAsDictionary["alert"] as Dictionary<string, object>;
                                    if (alertDescription != null && alertDescription.ContainsKey("text"))
                                    {
                                        alertText = alertDescription["text"].ToString();
                                    }
                                }
                                else if (errorAsDictionary.ContainsKey("data"))
                                {
                                    Dictionary<string, object> alertData = errorAsDictionary["data"] as Dictionary<string, object>;
                                    if (alertData != null && alertData.ContainsKey("text"))
                                    {
                                        alertText = alertData["text"].ToString();
                                    }
                                }
    
                                throw new UnhandledAlertException(errorMessage, alertText);
    
                            case WebDriverResult.NoAlertPresent:
                                throw new NoAlertPresentException(errorMessage);
    
                            case WebDriverResult.InvalidSelector:
                                throw new InvalidSelectorException(errorMessage);
    
                            case WebDriverResult.NoSuchDriver:
                                throw new WebDriverException(errorMessage);
    
                            case WebDriverResult.InvalidArgument:
                                throw new WebDriverArgumentException(errorMessage);
    
                            case WebDriverResult.UnexpectedJavaScriptError:
                                throw new JavaScriptException(errorMessage);
    
                            case WebDriverResult.MoveTargetOutOfBounds:
                                throw new MoveTargetOutOfBoundsException(errorMessage);
    
                            case WebDriverResult.NoSuchShadowRoot:
                                throw new NoSuchShadowRootException(errorMessage);
    
                            case WebDriverResult.DetachedShadowRoot:
                                throw new DetachedShadowRootException(errorMessage);
    
                            case WebDriverResult.InsecureCertificate:
                                throw new InsecureCertificateException(errorMessage);
    
                            case WebDriverResult.UnknownError:
                                throw new UnknownErrorException(errorMessage);
    
                            case WebDriverResult.UnsupportedOperation:
                                throw new UnsupportedOperationException(errorMessage);
    
                            default:
                                throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "{0} ({1})", errorMessage, errorResponse.Status));
                        }
                    }

    Copy link
    Contributor

    PR Code Suggestions ✨

    Explore these optional code suggestions:

    CategorySuggestion                                                                                                                                    Score
    General
    Enhance error reporting by providing structured error information instead of raw exception object

    Initialize the Response object with a meaningful error message when catching
    HttpRequestException. Currently only the exception object is stored, which may not
    provide clear context about the connection failure.

    dotnet/src/webdriver/WebDriver.cs [621-628]

     catch (System.Net.Http.HttpRequestException e)
     {
         commandResponse = new Response
         {
             Status = WebDriverResult.UnknownError,
    -        Value = e
    +        Value = new Dictionary<string, object>
    +        {
    +            { "message", "Failed to connect to WebDriver endpoint: " + e.Message },
    +            { "stackTrace", e.StackTrace },
    +            { "error", e }
    +        }
         };
     }
    • Apply this suggestion
    Suggestion importance[1-10]: 8

    Why: The suggestion significantly improves error diagnostics by providing structured, detailed error information instead of just passing the raw exception, making it easier to understand and debug connection issues.

    8
    Possible issue
    Add required serialization support for proper cross-AppDomain exception handling

    Add serialization constructor to support proper exception serialization across
    AppDomain boundaries, which is required for [Serializable] types.

    dotnet/src/webdriver/UnknownErrorException.cs [29-39]

     [Serializable]
     public class UnknownErrorException : WebDriverException
     {
    +    protected UnknownErrorException(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
    +        : base(info, context)
    +    {
    +    }
    +
         public UnknownErrorException(string? message)
             : base(message)
         {
         }
    • Apply this suggestion
    Suggestion importance[1-10]: 7

    Why: This is an important improvement for proper exception handling across AppDomain boundaries, as it adds the required serialization constructor for a [Serializable] type, preventing potential serialization issues.

    7

    @nvborisenko
    Copy link
    Member

    I guess we can move further reviewing it: at least 2 members think of it came from obsolete https://www.selenium.dev/documentation/legacy/json_wire_protocol, and python doesn't have this error code.

    @nvborisenko
    Copy link
    Member

    @RenderMichael I propose to expand this PR to align all actual error codes, not only UnhandledError if you can. Seems python state is more accurate: https://github.com/SeleniumHQ/selenium/blob/7854e62162d2f23d7fc0238ee4e8d6d54afca90e/py/selenium/webdriver/remote/errorhandler.py including custom exceptions.

    @nvborisenko nvborisenko changed the title [dotnet] Remove out-of-spec UnhandledError error status [dotnet] [breaking change] Remove out-of-spec UnhandledError error status Dec 24, 2024
    @RenderMichael RenderMichael changed the title [dotnet] [breaking change] Remove out-of-spec UnhandledError error status [dotnet] Align webdriver errors with spec Dec 26, 2024
    @nvborisenko
    Copy link
    Member

    Seems are deprecating "aggressively", I mean it will become to hard to manage when exactly we should remove deprecated code. I propose to just to append a hint when exactly it will be deprecated. Usually, as I understand deprecation policy, it is +2 minor releases.

    So instead of [Obsolete(....)] it will be better for everybody to see [Obsolete(... Will be removed in 4.30)] (where 4.27 is current).

    @nvborisenko
    Copy link
    Member

    Thanks @RenderMichael for the contribution!

    @nvborisenko nvborisenko merged commit 59f090b into SeleniumHQ:trunk Dec 26, 2024
    10 checks passed
    @RenderMichael RenderMichael deleted the unhandled-error branch December 26, 2024 21:01
    sandeepsuryaprasad pushed a commit to sandeepsuryaprasad/selenium that referenced this pull request Dec 27, 2024
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Projects
    None yet
    Development

    Successfully merging this pull request may close these issues.

    2 participants