Skip to content

D41197_Explore Issue Fixed#3935

Merged
prashelke merged 1 commit into
Releases/Official-Releasefrom
BugFix/ExplorerFix
Sep 26, 2024
Merged

D41197_Explore Issue Fixed#3935
prashelke merged 1 commit into
Releases/Official-Releasefrom
BugFix/ExplorerFix

Conversation

@prashelke

@prashelke prashelke commented Sep 26, 2024

Copy link
Copy Markdown
Contributor

Thank you for your contribution.
Before submitting this PR, please make sure:

  • PR description and commit message should describe the changes done in this PR
  • Verify the PR is pointing to correct branch i.e. Release or Beta branch if the code fix is for specific release , else point it to master
  • Latest Code from master or specific release branch is merged to your branch
  • No unwanted\commented\junk code is included
  • No new warning upon build solution
  • Code Summary\Comments are added to my code which explains what my code is doing
  • Existing unit test cases are passed
  • New Unit tests are added for your development
  • Sanity Tests are successfully executed for New and Existing Functionality
  • Verify that changes are compatible with all relevant browsers and platforms.
  • After creating pull request there should not be any conflicts
  • Resolve all Codacy comments
  • Builds and checks are passed before PR is sent for review
  • Resolve code review comments
  • Update the Help Library document to match any feature changes

Summary by CodeRabbit

  • Bug Fixes

    • Improved robustness of element property retrieval by adding null checks and default values for size and location.
    • Enhanced handling of element locators to ensure safer attribute retrieval.
  • Refactor

    • Updated methods to streamline element handling and improve error management.

@coderabbitai

coderabbitai Bot commented Sep 26, 2024

Copy link
Copy Markdown
Contributor

Walkthrough

The changes in this pull request focus on enhancing the GetElementProperties and GetElementLocators methods within the SeleniumDriver.cs file. Key modifications include improved null handling for element objects and attributes, ensuring that default values are provided when necessary. The retrieval of elements has been adjusted to prevent potential null reference exceptions, thereby increasing the robustness of the element handling in the Selenium driver.

Changes

File Path Change Summary
Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs Adjusted GetElementProperties and GetElementLocators methods for improved null handling and default value assignments.

Possibly related PRs

  • BugFix - 40481 - Disable by tag name locator #3917: This PR modifies the SeleniumDriver.cs file, specifically within the LearnElementInfoDetails method, which is closely related to the changes made in the GetElementProperties and GetElementLocators methods of the same file in the main PR.

Suggested reviewers

  • Maheshkale447

Poem

🐇 In the world of code, a rabbit hops,
Fixing bugs and making stops.
With checks for null and values bright,
Selenium's now a smoother flight!
Hooray for changes, let’s all cheer,
For robust drivers, we hold dear! 🐇


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai or @coderabbitai title anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Outside diff range and nitpick comments (26)
Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs (26)

Line range hint 1-77: Consider organizing imports and using statements

The file starts with a large number of using statements. Consider organizing these into logical groups (e.g., System namespaces, Selenium namespaces, project-specific namespaces) and potentially using global using statements in a separate file to reduce clutter.

global using System;
global using System.Collections.Generic;
global using System.Linq;
// ... other commonly used namespaces

// In this file:
using Amdocs.Ginger.Common;
using OpenQA.Selenium;
// ... other specific namespaces

Line range hint 79-85: Consider splitting large class into smaller, focused classes

The SeleniumDriver class is very large and seems to have multiple responsibilities. Consider splitting it into smaller, more focused classes to improve maintainability and readability.

For example, you could create separate classes for:

  • Browser management
  • Element location and interaction
  • JavaScript execution
  • Network monitoring

Line range hint 87-185: Refactor enum declarations

The enum declarations at the beginning of the class could be moved to separate files or a dedicated "Enums" class to improve organization.

Create a new file SeleniumEnums.cs:

public static class SeleniumEnums
{
    public enum eBrowserType { ... }
    public enum ePageLoadStrategy { ... }
    public enum eUnhandledPromptBehavior { ... }
    public enum eBrowserLogLevel { ... }
}

Then use these enums in the SeleniumDriver class.


Line range hint 187-326: Consider using auto-implemented properties

Many of the properties in this section could be simplified using auto-implemented properties. This would reduce code clutter and improve readability.

For example:

public string ProxyAutoConfigUrl { get; set; }
public bool EnableNativeEvents { get; set; } = false;
public bool AutoDetect { get; set; } = true;
// ... other properties

Line range hint 328-372: Improve error handling in BrowserType property

The BrowserType property uses a switch statement for both getter and setter. Consider using a dictionary or enum mapping to simplify this logic and make it more maintainable.

private static readonly Dictionary<WebBrowserType, eBrowserType> BrowserTypeMapping = new()
{
    { WebBrowserType.Chrome, eBrowserType.Chrome },
    { WebBrowserType.FireFox, eBrowserType.FireFox },
    // ... other mappings
};

public override WebBrowserType BrowserType
{
    get => BrowserTypeMapping.FirstOrDefault(x => x.Value == mBrowserType).Key;
    set
    {
        if (BrowserTypeMapping.TryGetValue(value, out var browserType))
        {
            mBrowserType = browserType;
        }
        else
        {
            throw new ArgumentException($"Unsupported browser type: {value}");
        }
    }
}

Line range hint 374-403: Consider using dependency injection for Driver

The Driver property is protected and seems to be a core component of this class. Consider using dependency injection to provide the IWebDriver instance, which would improve testability and flexibility.

public class SeleniumDriver
{
    private readonly IWebDriver _driver;

    public SeleniumDriver(IWebDriver driver)
    {
        _driver = driver ?? throw new ArgumentNullException(nameof(driver));
    }

    // Use _driver instead of Driver throughout the class
}

Line range hint 405-456: Simplify InitDriver method

The InitDriver method could be simplified by using a switch expression instead of if-else statements.

public override void InitDriver(Agent agent)
{
    if (BrowserType != WebBrowserType.RemoteWebDriver)
    {
        return;
    }

    if (agent.DriverConfiguration == null)
    {
        agent.DriverConfiguration = new ObservableList<DriverConfigParam>();
    }

    (RemoteGridHub, RemoteBrowserName, RemotePlatform, RemoteVersion) = (
        agent.GetParamValue(RemoteGridHubParam),
        agent.GetParamValue(RemoteBrowserNameParam),
        agent.GetParamValue(RemotePlatformParam),
        agent.GetParamValue(RemoteVersionParam)
    );

    if (WorkSpace.Instance.BetaFeatures.ShowHealenium)
    {
        (IsHealenium, HealeniumUrl) = (agent.Healenium, agent.HealeniumURL);
    }
}

Line range hint 458-483: Consider using a factory pattern for browser creation

The StartDriver method is quite long and complex. Consider using a factory pattern to create different browser instances based on the mBrowserType.

Create a BrowserFactory class:

public class BrowserFactory
{
    public IWebDriver CreateBrowser(eBrowserType browserType, BrowserOptions options)
    {
        return browserType switch
        {
            eBrowserType.Chrome => CreateChromeDriver(options),
            eBrowserType.FireFox => CreateFirefoxDriver(options),
            // ... other browser types
            _ => throw new ArgumentException($"Unsupported browser type: {browserType}")
        };
    }

    private IWebDriver CreateChromeDriver(BrowserOptions options) { ... }
    private IWebDriver CreateFirefoxDriver(BrowserOptions options) { ... }
    // ... other creation methods
}

Then use this factory in the StartDriver method.


Line range hint 485-1037: Refactor StartDriver method

The StartDriver method is extremely long and complex. It should be broken down into smaller, more focused methods for each browser type and common setup steps.

public override void StartDriver()
{
    SetupProxy();
    SetupImplicitWait();
    SetupSeleniumArguments();

    try
    {
        Driver = CreateDriverForBrowserType();
        SetupBrowserWindow();
        SetupTimeouts();
        InitializeDefaultState();
    }
    catch (Exception ex)
    {
        HandleDriverStartupException(ex);
    }
}

private IWebDriver CreateDriverForBrowserType()
{
    return mBrowserType switch
    {
        eBrowserType.IE => CreateInternetExplorerDriver(),
        eBrowserType.FireFox => CreateFirefoxDriver(),
        eBrowserType.Chrome => CreateChromeDriver(),
        // ... other browser types
        _ => throw new NotSupportedException($"Browser type {mBrowserType} is not supported.")
    };
}

private IWebDriver CreateInternetExplorerDriver() { ... }
private IWebDriver CreateFirefoxDriver() { ... }
private IWebDriver CreateChromeDriver() { ... }
// ... other creation methods

private void SetupBrowserWindow() { ... }
private void SetupTimeouts() { ... }
private void InitializeDefaultState() { ... }
private void HandleDriverStartupException(Exception ex) { ... }

Line range hint 1039-1106: Simplify UpdateDriver method

The UpdateDriver method could be simplified by using pattern matching and reducing nested if statements.

private string UpdateDriver(eBrowserType browserType)
{
    try
    {
        Reporter.ToLog(eLogLevel.INFO, $"Attempting to update {browserType} driver to latest using System Proxy Settings....");
        
        DriverOptions driverOptions = browserType switch
        {
            eBrowserType.Chrome => new ChromeOptions(),
            eBrowserType.Edge => new EdgeOptions(),
            eBrowserType.FireFox => new FirefoxOptions(),
            _ => throw new NotSupportedException($"Browser type {browserType} is not supported for driver update.")
        };

        SetupProxyForDriverUpdate(driverOptions);
        SetBrowserVersion(driverOptions);

        var driverFinder = new DriverFinder(driverOptions);
        var driverPath = driverFinder.GetDriverPath();
        
        Reporter.ToLog(eLogLevel.INFO, $"Updated {browserType} driver to latest and placed in {driverPath}.");
        return driverPath;
    }
    catch (Exception ex)
    {
        HandleDriverUpdateException(ex, browserType);
        throw;
    }
}

private void SetupProxyForDriverUpdate(DriverOptions driverOptions)
{
    string systemProxy = OperatingSystemBase.GetSystemProxy();
    if (!string.IsNullOrEmpty(systemProxy))
    {
        var proxy = new Proxy
        {
            Kind = ProxyKind.Manual,
            HttpProxy = systemProxy,
            SslProxy = systemProxy
        };
        driverOptions.Proxy = proxy;
    }
}

private void HandleDriverUpdateException(Exception ex, eBrowserType browserType)
{
    if (!WorkSpace.Instance.RunningInExecutionMode && !WorkSpace.Instance.RunningFromUnitTest)
    {
        Reporter.ToUser(eUserMsgKey.FailedToDownloadDriver, browserType);
    }
    Reporter.ToLog(eLogLevel.ERROR, string.Format(Reporter.UserMsgsPool[eUserMsgKey.FailedToDownloadDriver].Message, browserType), ex);
}

Line range hint 1108-1134: Simplify GetDriverPath method

The GetDriverPath method can be simplified to a one-liner.

public string GetDriverPath(eBrowserType browserType) => UpdateDriver(browserType);

Line range hint 1136-1155: Improve error handling in CloseDriverProcess

The CloseDriverProcess method swallows all exceptions. Consider logging the exception or handling specific exception types.

private static void CloseDriverProcess(DriverService driverService)
{
    if (driverService?.ProcessId == 0)
    {
        return;
    }

    try
    {
        Reporter.ToLog(eLogLevel.DEBUG, "Closing Driver process which was left open after failure to start driver.");
        var process = System.Diagnostics.Process.GetProcessById(driverService.ProcessId);
        process?.Kill();
    }
    catch (ArgumentException ex)
    {
        Reporter.ToLog(eLogLevel.DEBUG, $"Process with ID {driverService.ProcessId} not found. It may have already been closed.", ex);
    }
    catch (Exception ex)
    {
        Reporter.ToLog(eLogLevel.ERROR, $"Failed to close driver process with ID {driverService.ProcessId}", ex);
    }
}

Line range hint 1157-1186: Simplify GetDriversPathPerOS method

The GetDriversPathPerOS method can be simplified using pattern matching and removing redundant conditions.

public string GetDriversPathPerOS()
{
    string basePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);

    return Environment.OSVersion.Platform switch
    {
        PlatformID.Win32NT when Use64Bitbrowser && (mBrowserType == eBrowserType.IE || mBrowserType == eBrowserType.FireFox) 
            => Path.Combine(basePath, "Win64"),
        PlatformID.Win32NT or PlatformID.Unix or PlatformID.MacOSX 
            => basePath,
        _ => throw new PlatformNotSupportedException($"The '{RuntimeInformation.OSDescription}' OS is not supported by Ginger Selenium")
    };
}

Line range hint 1188-1218: Simplify DriverServiceFileName method

The DriverServiceFileName method can be simplified using pattern matching.

private string DriverServiceFileName(string fileName)
{
    return Environment.OSVersion.Platform switch
    {
        PlatformID.Win32NT => $"{fileName}.exe",
        PlatformID.Unix or PlatformID.MacOSX => fileName,
        _ => throw new PlatformNotSupportedException($"The '{RuntimeInformation.OSDescription}' OS is not supported by Ginger Selenium")
    };
}

Line range hint 1220-1223: Simplify AddByPassAddress method

The AddByPassAddress method can be simplified to a one-liner.

private string[] AddByPassAddress() => ByPassProxy.Split(';');

Line range hint 1225-1279: Refactor SetProxy method

The SetProxy method can be simplified by using a switch expression and extracting the proxy configuration logic.

private void SetProxy(dynamic options)
{
    if (mProxy == null)
    {
        return;
    }

    var proxy = new Proxy { Kind = mProxy.Kind };
    options.Proxy = proxy;

    ConfigureProxy(proxy);
}

private void ConfigureProxy(Proxy proxy)
{
    switch (proxy.Kind)
    {
        case ProxyKind.Manual:
            proxy.HttpProxy = mProxy.HttpProxy;
            proxy.SslProxy = mProxy.SslProxy;
            if (!string.IsNullOrEmpty(ByPassProxy))
            {
                proxy.AddBypassAddresses(AddByPassAddress());
            }
            break;
        case ProxyKind.ProxyAutoConfigure:
            proxy.ProxyAutoConfigUrl = mProxy.ProxyAutoConfigUrl;
            break;
        case ProxyKind.AutoDetect:
        case ProxyKind.System:
        case ProxyKind.Direct:
            // No additional configuration needed
            break;
        default:
            proxy.Kind = ProxyKind.System;
            break;
    }
}

Line range hint 1281-1314: Simplify CheckifPageLoaded method

The CheckifPageLoaded method can be simplified by using a more concise lambda expression.

void CheckifPageLoaded()
{
    WebDriverWait webDriverWait = new WebDriverWait(Driver, TimeSpan.FromSeconds(ImplicitWait));
    webDriverWait.Until(driver =>
    {
        var jQueryComplete = ((IJavaScriptExecutor)driver).ExecuteScript("return window.jQuery && jQuery.active == 0") as bool? ?? true;
        var documentReady = ((IJavaScriptExecutor)driver).ExecuteScript("return document.readyState").Equals("complete");
        return documentReady && jQueryComplete;
    });
}

Line range hint 1316-1321: Simplify GetCurrentElement method

The GetCurrentElement method can be simplified by using pattern matching and removing redundant null checks.

public override Act GetCurrentElement()
{
    try
    {
        IWebElement currentElement = Driver.SwitchTo().ActiveElement();
        return currentElement.TagName.ToLower() switch
        {
            "input" => HandleInputElement(currentElement),
            "a" => getActLink(currentElement),
            _ => null
        };
    }
    catch (Exception ex)
    {
        Reporter.ToLog(eLogLevel.ERROR, "Exception occurred while getting current element", ex);
        return null;
    }
}

private Act HandleInputElement(IWebElement element)
{
    return element.GetAttribute("type").ToLower() switch
    {
        "text" => getActTextBox(element),
        "button" or "submit" => getActButton(element),
        "password" => getActPassword(element),
        "checkbox" => getActCheckbox(element),
        "radio" => getActRadioButton(element),
        _ => null
    };
}

Line range hint 1323-1485: Refactor element handling methods

The methods for handling different element types (e.g., getActButton, getActPassword, etc.) can be refactored to reduce code duplication and improve consistency.

Create a base method for common element handling:

private Act CreateBaseAct<T>(IWebElement element) where T : Act, new()
{
    var act = new T();
    act.LocateBy = eLocateBy.ByID;
    act.LocateValue = element.GetAttribute("id");
    return act;
}

private Act getActButton(IWebElement element)
{
    return CreateBaseAct<ActButton>(element);
}

private Act getActPassword(IWebElement element)
{
    var act = CreateBaseAct<ActPassword>(element);
    (act as ActPassword).PasswordAction = ActPassword.ePasswordAction.SetValue;
    act.AddOrUpdateInputParamValue("Value", element.GetAttribute("value"));
    act.AddOrUpdateReturnParamActual("Actual", $"Tag Name = {element.TagName}");
    return act;
}

// Similar refactoring for other element handling methods

Line range hint 1487-1559: Refactor GotoURL method

The GotoURL method can be simplified and improved for better error handling and readability.

private void GotoURL(Act act, string sURL)
{
    if (string.IsNullOrEmpty(sURL))
    {
        act.Error = "Error: Provided URL is empty. Please provide valid URL.";
        return;
    }

    try
    {
        Uri uri = new Uri(sURL.StartsWith("www", StringComparison.OrdinalIgnoreCase) ? $"http://{sURL}" : sURL);
        Driver.Navigate().GoToUrl(uri.AbsoluteUri);
        
        HandleCertificateError();
        CheckifPageLoaded();
    }
    catch (UriFormatException)
    {
        act.Error = "Error: Invalid URL. Please provide a valid URL (complete URL).";
    }
    catch (Exception ex)
    {
        act.Status = Amdocs.Ginger.CoreNET.Execution.eRunStatus.Failed;
        act.Error = $"Error navigating to URL: {ex.Message}";
    }
}

private void HandleCertificateError()
{
    if (Driver is InternetExplorerDriver && Driver.Title.Contains("Certificate Error", StringComparison.OrdinalIgnoreCase))
    {
        Thread.Sleep(100);
        try
        {
            Driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds(1);
            Driver.Navigate().GoToUrl("javascript:document.getElementById('overridelink').click()");
        }
        catch
        {
            // Ignore exceptions when handling certificate errors
        }
        finally
        {
            Driver.Manage().Timeouts().ImplicitWait = TimeSpan.FromSeconds((int)ImplicitWait);
        }
    }
}

Line range hint 1561-1566: Simplify GetURL method

The GetURL method can be simplified to a one-liner.

public override string GetURL() => Driver.Url;

Line range hint 1568-2080: Refactor RunAction method

The RunAction method is very long and complex. It should be refactored into smaller, more focused methods for better maintainability and readability.

public override void RunAction(Act act)
{
    if (!ShouldRunActionDirectly(act))
    {
        PrepareDriverForAction(act);
    }

    try
    {
        ExecuteAction(act);
    }
    catch (Exception ex)
    {
        HandleActionException(act, ex);
    }
}

private bool ShouldRunActionDirectly(Act act)
{
    // Logic to determine if the action should be run directly
}

private void PrepareDriverForAction(Act act)
{
    EnsureDriverIsAccessible();
    SetImplicitWait(act);
    SetupBrowserMobProxy(act);
}

private void ExecuteAction(Act act)
{
    switch (act)
    {
        case ActUIElement actUIElement:
            HandleActUIElement(actUIElement);
            break;
        case ActGotoURL actGotoURL:
            GotoURL(actGotoURL, actGotoURL.GetInputParamCalculatedValue("Value"));
            break;
        // ... other action types
        default:
            throw new NotSupportedException($"Action type {act.GetType()} is not supported.");
    }
}

private void HandleActionException(Act act, Exception ex)
{
    act.Status = Amdocs.Ginger.CoreNET.Execution.eRunStatus.Failed;
    act.Error = ex.Message;
    Reporter.ToLog(eLogLevel.ERROR, $"Error executing action: {act.Description}", ex);
}

Line range hint 2082-2156: Refactor element locating methods

The methods for locating elements (e.g., LocateElement, LocateElementByLocators, etc.) are complex and could benefit from refactoring for better readability and maintainability.

Create a separate ElementLocator class to handle element location strategies:

public class ElementLocator
{
    private readonly IWebDriver _driver;
    private readonly ISearchContext _searchContext;

    public ElementLocator(IWebDriver driver, ISearchContext searchContext = null)
    {
        _driver = driver;
        _searchContext = searchContext ?? driver;
    }

    public IWebElement LocateElement(ElementInfo elementInfo)
    {
        if (elementInfo.LocateBy == eLocateBy.POMElement)
        {
            return LocatePOMElement(elementInfo);
        }

        return LocateElementByLocator(elementInfo.Locators.FirstOrDefault(l => l.Active));
    }

    private IWebElement LocatePOMElement(ElementInfo elementInfo)
    {
        // POM element location logic
    }

    private IWebElement LocateElementByLocator(ElementLocator locator)
    {
        // Element location logic based on locator type
    }

    // Other helper methods for element location
}

Then use this class in the SeleniumDriver:

private ElementLocator _elementLocator;

public SeleniumDriver()
{
    // ... other initialization
    _elementLocator = new ElementLocator(Driver);
}

public IWebElement LocateElement(Act act)
{
    return _elementLocator.LocateElement(act);
}

Line range hint 2158-2280: Refactor GetElementTypeEnum method

The GetElementTypeEnum method is complex and uses a lot of if-else statements. It can be simplified using pattern matching and a more structured approach.

public static Tuple<string, eElementType> GetElementTypeEnum(IWebElement el = null, string jsType = null, HtmlNode htmlNode = null)
{
    string elementTagName = GetElementTagName(el, jsType, htmlNode);
    string elementTypeAtt = GetElementTypeAttribute(el, htmlNode);

    eElementType elementType = GetElementType(elementTagName, elementTypeAtt);

    return new Tuple<string, eElementType>(elementTagName, elementType);
}

private static string GetElementTagName(IWebElement el, string jsType, HtmlNode htmlNode)
{
    return el?.TagName?.ToUpper()
        ?? jsType
        ?? htmlNode?.Name
        ?? "INPUT";
}

private static string GetElementTypeAttribute(IWebElement el, HtmlNode htmlNode)
{
    return el?.GetAttribute("type")
        ?? htmlNode?.Attributes["type"]?.Value
        ?? string.Empty;
}

private static eElementType GetElementType(string elementTagName, string elementTypeAtt)
{
    return (elementTagName, elementTypeAtt.ToUpper()) switch
    {
        ("INPUT", "TEXT") or ("INPUT", "PASSWORD") or ("INPUT", "EMAIL") or ("INPUT", "TEL") or ("INPUT", "SEARCH") or ("INPUT", "NUMBER") or ("INPUT", "URL") or ("INPUT", "DATE") => eElementType.TextBox,
        ("INPUT", "IMAGE") or ("INPUT", "SUBMIT") or ("INPUT", "BUTTON") => eElementType.Button,
        ("INPUT", "CHECKBOX") => eElementType.CheckBox,
        ("INPUT", "RADIO") => eElementType.RadioButton,
        ("TEXTAREA", _) or ("TEXT", _) => eElementType.TextBox,
        ("BUTTON", _) or ("RESET", _) or ("SUBMIT", _) => eElementType.Button,
        ("TD", _) or ("TH", _) or ("TR", _) => eElementType.TableItem,
        ("LINK", _) or ("A", _) or ("LI", _) => eElementType.HyperLink,
        ("LABEL", _) or ("TITLE", _) => eElementType.Label,
        ("SELECT", _) or ("SELECT-ONE", _) => eElementType.ComboBox,
        ("TABLE", _) or ("CAPTION", _) => eElementType.Table,
        ("JEDITOR.TABLE", _) => eElementType.EditorPane,
        ("DIV", _) => eElementType.Div,
        ("SPAN", _) => eElementType.Span,
        ("IMG", _) or ("MAP", _) => eElementType.Image,
        ("OPTGROUP", _) or ("OPTION", _) => eElementType.ComboBoxOption,
        ("IFRAME", _) or ("FRAME", _) or ("FRAMESET", _) => eElementType.Iframe,
        ("CANVAS", _) => eElementType.Canvas,
        ("FORM", _) => eElementType.Form,
        ("UL", _) or ("OL", _) or ("DL", _) => eElementType.List,
        ("LI", _) or ("DT", _) or ("DD", _) => eElementType.ListItem,
        ("MENU", _) => eElementType.MenuBar,
        ("H1", _) or ("H2", _) or ("H3", _) or ("H4", _) or ("H5", _) or ("H6", _) or ("P", _) => eElementType.Text,
        ("SVG", _) => eElementType.Svg,
        _ => eElementType.Unknown
    };
}

Line range hint 2282-2359: Refactor LearnElementInfoDetails method

The LearnElementInfoDetails method is complex and performs multiple operations. It can be refactored into smaller, more focused methods for better readability and maintainability.

ElementInfo IWindowExplorer.LearnElementInfoDetails(ElementInfo EI, PomSetting pomSetting)
{
    UpdateElementType(EI);
    UpdateElementXPath(EI, pomSetting);
    UpdateElementName(EI);
    UpdateElementRelXPath(EI, pomSetting);
    UpdateElementLocators(EI, pomSetting);
    UpdateElementProperties(EI);

    return EI;
}

private void UpdateElementType(ElementInfo EI)
{
    if (string.IsNullOrEmpty(EI.ElementType) || EI.ElementTypeEnum == eElementType.Unknown)
    {
        var elementTypeEnum = GetElementTypeEnum(EI.ElementObject as IWebElement);
        EI.ElementType = elementTypeEnum.Item1;
        EI.ElementTypeEnum = elementTypeEnum.Item2;
    }
}

private void UpdateElementXPath(ElementInfo EI, PomSetting pomSetting)
{
    if (string.IsNullOrEmpty(EI.XPath) || EI.XPath == "/")
    {
        EI.XPath = GenerateXPathForElement(EI);
    }
}

private void UpdateElementName(ElementInfo EI)
{
    EI.ElementName = GetElementName(EI as HTMLElementInfo);
}

private void UpdateElementRelXPath(ElementInfo EI, PomSetting pomSetting)
{
    if (mXPathHelper == null)
    {
        InitXpathHelper();
    }
    ((HTMLElementInfo)EI).RelXpath = mXPathHelper.GetElementRelXPath(EI, pomSetting);
}

private void UpdateElementLocators(ElementInfo EI, PomSetting pomSetting)
{
    EI.Locators = ((IWindowExplorer)this).GetElementLocators(EI, pomSetting);
    if (EI.Locators.Any(x => x.EnableFriendlyLocator))
    {
        EI.FriendlyLocators = ((IWindowExplorer)this).GetElementFriendlyLocators(EI, pomSetting);
    }
}

private void UpdateElementProperties(ElementInfo EI)
{
    EI.Properties = ((IWindowExplorer)this).GetElementProperties(EI);
}

Line range hint 2361-2424: Refactor GetElementName method

The GetElementName method can be simplified and made more readable by using LINQ and reducing nested if statements.

private string GetElementName(HTMLElementInfo EI)
{
    if (EI.HTMLElementObject == null)
    {
        return string.IsNullOrEmpty(EI.Value) ? EI.ElementTypeEnumDescription : null;
    }

    var attributes = new[]
    {
        EI.HTMLElementObject.Name,
        EI.HTMLElementObject.Attributes["name"]?.Value,
        EI.HTMLElementObject.Attributes["title"]?.Value,
        E

</blockquote></details>

</blockquote></details>

<details>
<summary>:scroll: Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**

<details>
<summary>:inbox_tray: Commits</summary>

Files that changed from the base of the PR and between 2304e9330db4f33dbc813e48d08846b7e8366f50 and 1ce2574381ed4d5c0eaf6274127276293807c901.

</details>

<details>
<summary>:ledger: Files selected for processing (1)</summary>

* Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs (5 hunks)

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->

@prashelke
prashelke merged commit 4dadc87 into Releases/Official-Release Sep 26, 2024
@prashelke
prashelke deleted the BugFix/ExplorerFix branch September 26, 2024 17:40
@coderabbitai coderabbitai Bot mentioned this pull request Jul 10, 2025
15 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants