Skip to content

Selenium upgrade#4461

Merged
ravirk91 merged 4 commits into
masterfrom
Enhancement/SeleniumUpgrade
Mar 11, 2026
Merged

Selenium upgrade#4461
ravirk91 merged 4 commits into
masterfrom
Enhancement/SeleniumUpgrade

Conversation

@AmanPrasad43

@AmanPrasad43 AmanPrasad43 commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

Description

Type of Change

  • Bug fix - [ ] New feature - [ ] Breaking change - [ ] Plugin update

Checklist

  • PR description clearly describes the changes
  • Target branch is correct (master for features, Releases/* for fixes)
  • Latest code from target branch merged
  • No commented/junk code included
  • No new build warnings or errors
  • All existing unit tests pass
  • New unit tests added for new functionality
  • Cross-platform compatibility verified (Windows/Linux/macOS)
  • CI/CD pipeline passes
  • Code follows project conventions (Act{Platform}{Type}, {Platform}Driver)
  • Repository objects use [IsSerializedForLocalRepository] where needed
  • Error handling uses Reporter.ToLog() pattern
  • Documentation updated for user-facing changes
  • Self-review completed and code review comments addressed

Summary by CodeRabbit

  • Dependencies

    • Selenium WebDriver packages updated to 4.41.0.
  • Improvements

    • Driver update and driver-path resolution are now asynchronous for improved responsiveness; UI file retrieval flows updated to await results.
    • DevTools protocol bumped to a newer version for broader browser compatibility.
  • Changes

    • FTP proxy entries in proxy configuration disabled.
  • Tests

    • Driver-path tests converted to async; repository test tightened to assert expected item count.
  • Chores

    • Removed an unused DevTools import.

@coderabbitai

coderabbitai Bot commented Mar 11, 2026

Copy link
Copy Markdown
Contributor

Walkthrough

Converted driver update/retrieval APIs to async, updated callers (UI and tests) to await GetDriverPath/UpdateDriver, bumped Selenium to 4.41.0, changed DevTools alias to V145, commented out FTP proxy assignments, and removed one unused DevTools using.

Changes

Cohort / File(s) Summary
Selenium Driver Core
Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs
Converted GetDriverPath and UpdateDriver to async (Task<string>), updated internal call sites to await results, switched DevTools alias to OpenQA.Selenium.DevTools.V145, and commented out FtpProxy assignments.
UI: Remote WebDriver Edit Page
Ginger/Ginger/Drivers/DriversConfigsEditPages/SeleniumRemoteWebDriverEditPage.xaml.cs
Made GetNodeFilesButton_Click async and awaited GetDriverPath(...) for browser drivers before performing file-copy logic.
Unit Tests
Ginger/GingerCoreNETUnitTest/SeleniumDriverTest/GetDriverPathTest.cs
Updated three test methods to return async Task and added await for GetDriverPath calls.
Dependencies & Cleanup
Ginger/GingerCoreNET/GingerCoreNET.csproj, Ginger/GingerCoreNET/GeneralLib/GingerPlayUtils.cs
Bumped Selenium packages to 4.41.0 and removed an unused OpenQA.Selenium.DevTools.V137.Audits using.
Other Tests
Ginger/GingerCoreCommonTest/Repository/SolutionRepositoryMultiThreadTest.cs
Added an assertion checking GetAllRepositoryItems returns expected count (106).

Sequence Diagram(s)

sequenceDiagram
    participant UI as "UI (EditPage)"
    participant SeleniumDrv as "SeleniumDriver"
    participant DriverFinder as "DriverFinder / Selenium Manager"
    participant FS as "FileSystem"

    UI->>SeleniumDrv: GetDriverPath(browserType) (await)
    SeleniumDrv->>DriverFinder: GetDriverPathAsync(browserType)
    DriverFinder-->>SeleniumDrv: driverPath (async)
    SeleniumDrv-->>UI: driverPath (awaited result)
    UI->>FS: copy driver files to node folder
    FS-->>UI: copy result
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

Suggested reviewers

  • Maheshkale447

Poem

🐰 I hopped to async with nimble feet,

Awaiting paths where drivers meet.
DevTools now hum V145's tune,
FTP naps beneath the moon,
Files copied — carrot-cake treat! 🥕

🚥 Pre-merge checks | ❌ 5

❌ Failed checks (3 warnings, 2 inconclusive)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description contains only the unfilled template with all checkboxes unchecked and no actual description of the changes, objectives, or verification details provided. Fill in the Description section with details about Selenium upgrade, asynchronous driver operations, and clarify the Type of Change. Check appropriate checklist items.
Out of Scope Changes check ⚠️ Warning The PR includes unrelated changes like removing an unused using directive and adding an assertion to an existing test, which appear to be scope creep. Isolate the Selenium upgrade and async refactoring changes into this PR. Move cleanup and unrelated test assertions into separate PRs.
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Selenium upgrade' is vague and does not clearly convey the primary changes, which include making driver operations asynchronous and updating Selenium dependencies. Consider a more specific title that reflects the main changes, such as 'Make Selenium driver operations asynchronous' or 'Upgrade Selenium to 4.41.0 and make driver path retrieval async'.
Linked Issues check ❓ Inconclusive The PR objectives indicate no linked issues or related work items are referenced, limiting traceability of the motivation and scope. Link the PR to relevant GitHub issues or work items that motivated this Selenium upgrade and asynchronous refactoring.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch Enhancement/SeleniumUpgrade

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@AmanPrasad43 AmanPrasad43 requested a review from ravirk91 March 11, 2026 09:18

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (4)
Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs (2)

1322-1378: ⚠️ Potential issue | 🔴 Critical

Use browserType here; mBrowserType makes the new API return the wrong driver.

GetDriverPath(eBrowserType browserType) now accepts an explicit browser, but UpdateDriver() still switches and reports on the instance field. A default-constructed SeleniumDriver will therefore treat every request as IE and return "" for Chrome/Edge/Firefox.

🛠️ Suggested fix
 private async Task<string> UpdateDriver(eBrowserType browserType)
 {
     try
     {
-        Reporter.ToLog(eLogLevel.INFO, $"Failed to Download latest {mBrowserType} driver. Attempting to Update {mBrowserType} driver to latest using System Proxy Settings....");
+        Reporter.ToLog(eLogLevel.INFO, $"Failed to download latest {browserType} driver. Attempting to update {browserType} driver to latest using System Proxy Settings....");
         DriverOptions driverOptions = null;

-        driverOptions = mBrowserType switch
+        driverOptions = browserType switch
         {
             eBrowserType.Chrome => new ChromeOptions(),
             eBrowserType.Edge => new EdgeOptions(),
             eBrowserType.FireFox => new FirefoxOptions(),
             _ => null
@@
                 if (!WorkSpace.Instance.RunningInExecutionMode && !WorkSpace.Instance.RunningFromUnitTest)
                 {
-                    Reporter.ToUser(eUserMsgKey.FailedToDownloadDriver, mBrowserType);
+                    Reporter.ToUser(eUserMsgKey.FailedToDownloadDriver, browserType);
                 }
-                Reporter.ToLog(eLogLevel.ERROR, string.Format(Reporter.UserMsgsPool[eUserMsgKey.FailedToDownloadDriver].Message, mBrowserType), ex);
+                Reporter.ToLog(eLogLevel.ERROR, string.Format(Reporter.UserMsgsPool[eUserMsgKey.FailedToDownloadDriver].Message, browserType), ex);
                 throw;
             }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs`
around lines 1322 - 1378, The issue is UpdateDriver uses the instance field
mBrowserType instead of the method parameter browserType causing wrong behavior;
update all references so the method operates on the passed-in browserType:
change the switch that builds driverOptions to use browserType (not
mBrowserType), update Reporter.ToLog messages to use browserType, and ensure
SetBrowserVersion is called with the explicit browserType (or use an overload
that accepts browserType) instead of relying on mBrowserType; also update the
error handling Reporter.ToUser and the formatted error message
(Reporter.UserMsgsPool[eUserMsgKey.FailedToDownloadDriver].Message) to supply
browserType so logs and user messages refer to the correct browser.

505-511: ⚠️ Potential issue | 🟠 Major

Implement IDisposable pattern; do not call blocking cleanup from the finalizer.

The finalizer invokes CloseDriver(), which blocks on async operations via .GetAwaiter().GetResult() (line 1554). Running blocking/async teardown on the finalizer thread can stall garbage collection and cause resource leaks. Instead, implement IDisposable on SeleniumDriver and move deterministic cleanup there, keeping the finalizer minimal or removing it entirely. Callers should be responsible for calling Dispose() explicitly.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs`
around lines 505 - 511, The finalizer (~SeleniumDriver) currently calls
CloseDriver() which blocks on async teardown; change SeleniumDriver to implement
IDisposable and move all blocking/async cleanup calls out of the finalizer into
a Dispose implementation: add a public void Dispose() that calls a private
Dispose(bool disposing) which performs CloseDriver() (safely awaiting or calling
the synchronous equivalent) when disposing is true, call
GC.SuppressFinalize(this) in Dispose(), and remove or make the finalizer
non-blocking (or remove it entirely) so that CloseDriver() is no longer invoked
on the finalizer thread; reference the SeleniumDriver class, the existing
~SeleniumDriver(), CloseDriver(), and implement IDisposable and Dispose(bool)
pattern accordingly.
Ginger/Ginger/Drivers/DriversConfigsEditPages/SeleniumRemoteWebDriverEditPage.xaml.cs (2)

186-186: 🧹 Nitpick | 🔵 Trivial

Remove unused variable driversSourcePath.

This variable is assigned but never used. It appears to be leftover from before the refactoring to use GetDriverPath() which now returns the full path directly.

♻️ Proposed fix
-            string driversSourcePath = assemblyLocation;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@Ginger/Ginger/Drivers/DriversConfigsEditPages/SeleniumRemoteWebDriverEditPage.xaml.cs`
at line 186, Remove the unused local variable driversSourcePath that is assigned
from assemblyLocation in SeleniumRemoteWebDriverEditPage.xaml.cs; the code now
uses GetDriverPath() which returns the full path, so delete the
declaration/assignment "string driversSourcePath = assemblyLocation;" and ensure
no other code references driversSourcePath (if any do, replace with
GetDriverPath() or the correct variable).

162-256: ⚠️ Potential issue | 🟠 Major

Wrap async operations in try-catch to prevent unhandled exceptions.

The async void event handler lacks exception handling. If any of the awaited GetDriverPath calls or subsequent file operations fail, the exception will propagate unhandled to the synchronization context, potentially crashing the application or leaving the UI in an inconsistent state.

🛡️ Proposed fix to add exception handling
 private async void GetNodeFilesButton_Click(object sender, RoutedEventArgs e)
 {
+    try
+    {
         //Getting the Ginger execution path
         string? assemblyLocation = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
         // ... existing code ...
         
         //Open Dialog folder
         Process.Start(new ProcessStartInfo() { FileName = targetZipPath, UseShellExecute = true });
+    }
+    catch (Exception ex)
+    {
+        Reporter.ToLog(eLogLevel.ERROR, "Failed to get node files", ex);
+    }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@Ginger/Ginger/Drivers/DriversConfigsEditPages/SeleniumRemoteWebDriverEditPage.xaml.cs`
around lines 162 - 256, GetNodeFilesButton_Click contains awaited calls
(SeleniumDriver.GetDriverPath) and file IO that can throw; wrap the entire
method body in a try-catch to prevent unhandled exceptions: surround the
existing code in GetNodeFilesButton_Click with try { ... } catch (Exception ex)
{ Reporter.ToLog(eLogLevel.ERROR, $"GetNodeFilesButton_Click failed: {ex}"); /*
optionally show a user-friendly MessageBox */ } so all exceptions from await
seleniumDriver.GetDriverPath(...) and System.IO operations are caught and
logged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs`:
- Around line 1382-1385: GetDriverPath and UpdateDriver were converted to async
Task<string> but callers remain synchronous; update all callers to await the
async results or revert signatures. Specifically, in tests (GetDriverPathTest.cs
where lines assign string DriverPath = driver.GetDriverPath(...)) change those
to await the async call and make the test methods async, and in SeleniumDriver
exception path (where UpdateDriver(mBrowserType) is invoked before
StartDriver()) await UpdateDriver(mBrowserType) so the driver update completes
before calling StartDriver(); ensure any call sites that expect a string now use
await and propagate async up the call chain or change the methods back to
synchronous signatures consistently.

In `@Ginger/GingerCoreNET/GingerCoreNET.csproj`:
- Around line 335-336: Update the Selenium.Support package reference to match
Selenium.WebDriver's version: change the PackageReference for "Selenium.Support"
(the element with Include="Selenium.Support") from 4.35.0 to 4.41.0 so both
PackageReference entries use version 4.41.0, ensuring dependency compatibility
between Selenium.Support and Selenium.WebDriver.

---

Outside diff comments:
In
`@Ginger/Ginger/Drivers/DriversConfigsEditPages/SeleniumRemoteWebDriverEditPage.xaml.cs`:
- Line 186: Remove the unused local variable driversSourcePath that is assigned
from assemblyLocation in SeleniumRemoteWebDriverEditPage.xaml.cs; the code now
uses GetDriverPath() which returns the full path, so delete the
declaration/assignment "string driversSourcePath = assemblyLocation;" and ensure
no other code references driversSourcePath (if any do, replace with
GetDriverPath() or the correct variable).
- Around line 162-256: GetNodeFilesButton_Click contains awaited calls
(SeleniumDriver.GetDriverPath) and file IO that can throw; wrap the entire
method body in a try-catch to prevent unhandled exceptions: surround the
existing code in GetNodeFilesButton_Click with try { ... } catch (Exception ex)
{ Reporter.ToLog(eLogLevel.ERROR, $"GetNodeFilesButton_Click failed: {ex}"); /*
optionally show a user-friendly MessageBox */ } so all exceptions from await
seleniumDriver.GetDriverPath(...) and System.IO operations are caught and
logged.

In `@Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs`:
- Around line 1322-1378: The issue is UpdateDriver uses the instance field
mBrowserType instead of the method parameter browserType causing wrong behavior;
update all references so the method operates on the passed-in browserType:
change the switch that builds driverOptions to use browserType (not
mBrowserType), update Reporter.ToLog messages to use browserType, and ensure
SetBrowserVersion is called with the explicit browserType (or use an overload
that accepts browserType) instead of relying on mBrowserType; also update the
error handling Reporter.ToUser and the formatted error message
(Reporter.UserMsgsPool[eUserMsgKey.FailedToDownloadDriver].Message) to supply
browserType so logs and user messages refer to the correct browser.
- Around line 505-511: The finalizer (~SeleniumDriver) currently calls
CloseDriver() which blocks on async teardown; change SeleniumDriver to implement
IDisposable and move all blocking/async cleanup calls out of the finalizer into
a Dispose implementation: add a public void Dispose() that calls a private
Dispose(bool disposing) which performs CloseDriver() (safely awaiting or calling
the synchronous equivalent) when disposing is true, call
GC.SuppressFinalize(this) in Dispose(), and remove or make the finalizer
non-blocking (or remove it entirely) so that CloseDriver() is no longer invoked
on the finalizer thread; reference the SeleniumDriver class, the existing
~SeleniumDriver(), CloseDriver(), and implement IDisposable and Dispose(bool)
pattern accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 1cd0c843-824a-4d33-93dc-c0db1ad0fe9b

📥 Commits

Reviewing files that changed from the base of the PR and between 0284e27 and 7a46eea.

📒 Files selected for processing (4)
  • Ginger/Ginger/Drivers/DriversConfigsEditPages/SeleniumRemoteWebDriverEditPage.xaml.cs
  • Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs
  • Ginger/GingerCoreNET/GeneralLib/GingerPlayUtils.cs
  • Ginger/GingerCoreNET/GingerCoreNET.csproj
💤 Files with no reviewable changes (1)
  • Ginger/GingerCoreNET/GeneralLib/GingerPlayUtils.cs

Comment on lines +1382 to 1385
public async Task<string> GetDriverPath(eBrowserType browserType)
{
string DriverPath = string.Empty;
DriverPath = UpdateDriver(browserType);
string DriverPath = await UpdateDriver(browserType);
return DriverPath;

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.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# List all current call sites for the newly-async APIs and highlight usages that are not obviously awaited.
rg -n -C2 '\b(GetDriverPath|UpdateDriver)\s*\(' --glob '*.cs'

printf '\nPotentially synchronous call sites:\n'
rg -nP --glob '*.cs' '^(?!.*\b(await|GetAwaiter\s*\(\)\.GetResult\s*\(\)|\.Result\b)).*\b(GetDriverPath|UpdateDriver)\s*\('

Repository: Ginger-Automation/Ginger

Length of output: 8176


Fix incomplete async migration: GetDriverPath and UpdateDriver have synchronous callers that will fail to compile and cause runtime races.

GetDriverPath and UpdateDriver are now async (Task<string>), but two categories of callers were not updated:

  1. Test compilation errors in GetDriverPathTest.cs (lines 39, 47, 55): Test methods assign the result directly to string without await:

    string DriverPath = driver.GetDriverPath(SeleniumDriver.eBrowserType.Chrome);
  2. Fire-and-forget race condition in SeleniumDriver.cs (line 1163): Within an exception handler before retry, UpdateDriver(mBrowserType) is called without await:

    UpdateDriver(mBrowserType);
    StartDriver();

    This will not wait for the driver update to complete before attempting to start the driver.

Either revert these methods to synchronous signatures or update all callers to properly await the results.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs`
around lines 1382 - 1385, GetDriverPath and UpdateDriver were converted to async
Task<string> but callers remain synchronous; update all callers to await the
async results or revert signatures. Specifically, in tests (GetDriverPathTest.cs
where lines assign string DriverPath = driver.GetDriverPath(...)) change those
to await the async call and make the test methods async, and in SeleniumDriver
exception path (where UpdateDriver(mBrowserType) is invoked before
StartDriver()) await UpdateDriver(mBrowserType) so the driver update completes
before calling StartDriver(); ensure any call sites that expect a string now use
await and propagate async up the call chain or change the methods back to
synchronous signatures consistently.

Comment thread Ginger/GingerCoreNET/GingerCoreNET.csproj Outdated
ravirk91
ravirk91 previously approved these changes Mar 11, 2026

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
Ginger/Ginger/Drivers/DriversConfigsEditPages/SeleniumRemoteWebDriverEditPage.xaml.cs (1)

163-243: ⚠️ Potential issue | 🟠 Major

Prevent overlapping package generations in this async handler.

After Line 163, the dispatcher can accept another click while the first run is awaiting GetDriverPath(...). This method still writes to the shared ...\Temp\GingerTemp / ...\Temp\Ginger folders and deletes them at the end, so concurrent runs can race on file copy, zip creation, and directory deletion and leave a broken package.

🛠️ Suggested fix
+        private static readonly System.Threading.SemaphoreSlim _nodePackageLock = new(1, 1);
+
         private async void GetNodeFilesButton_Click(object sender, RoutedEventArgs e)
         {
-            //Getting the Ginger execution path
-            string? assemblyLocation = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
-            string userFolder = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
-            string sourcePath = Path.Combine(assemblyLocation, "StaticDrivers");
-            string targetPath = userFolder + "\\Temp\\GingerTemp";
-            string jarFileName = "selenium-server-standalone.jar";
-            string sourceFile = System.IO.Path.Combine(sourcePath, jarFileName);
-            string destFile = System.IO.Path.Combine(targetPath, jarFileName);
+            await _nodePackageLock.WaitAsync();
+            try
+            {
+                //Getting the Ginger execution path
+                string? assemblyLocation = Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location);
+                string userFolder = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
+                string sourcePath = Path.Combine(assemblyLocation, "StaticDrivers");
+                string targetPath = Path.Combine(userFolder, "Temp", "GingerTemp", Guid.NewGuid().ToString("N"));
+                string jarFileName = "selenium-server-standalone.jar";
+                string sourceFile = System.IO.Path.Combine(sourcePath, jarFileName);
+                string destFile = System.IO.Path.Combine(targetPath, jarFileName);
 
-            // existing body
+                // existing body
+            }
+            finally
+            {
+                _nodePackageLock.Release();
+            }
         }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@Ginger/Ginger/Drivers/DriversConfigsEditPages/SeleniumRemoteWebDriverEditPage.xaml.cs`
around lines 163 - 243, GetNodeFilesButton_Click can be re-entered while
awaiting GetDriverPath which causes race conditions on the shared temp folder
(targetPath) and zip operations; prevent overlapping runs by gating the handler
with a reentrancy guard: add a private bool or SemaphoreSlim (e.g.,
_isGettingNodeFiles or _getNodeFilesLock) checked at the start of
GetNodeFilesButton_Click to return immediately if already running, set it before
any await and clear it in a finally block (or Release the semaphore), and also
optionally disable/enable the UI button control within the same try/finally so
concurrent clicks cannot start a second execution while file copy/zip/delete
operations (targetPath, chromeDestFile, fireFoxDestFile, IEDestFile,
edgeSourceFile, and any subsequent zip/delete code) are in progress.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In
`@Ginger/Ginger/Drivers/DriversConfigsEditPages/SeleniumRemoteWebDriverEditPage.xaml.cs`:
- Around line 163-243: GetNodeFilesButton_Click can be re-entered while awaiting
GetDriverPath which causes race conditions on the shared temp folder
(targetPath) and zip operations; prevent overlapping runs by gating the handler
with a reentrancy guard: add a private bool or SemaphoreSlim (e.g.,
_isGettingNodeFiles or _getNodeFilesLock) checked at the start of
GetNodeFilesButton_Click to return immediately if already running, set it before
any await and clear it in a finally block (or Release the semaphore), and also
optionally disable/enable the UI button control within the same try/finally so
concurrent clicks cannot start a second execution while file copy/zip/delete
operations (targetPath, chromeDestFile, fireFoxDestFile, IEDestFile,
edgeSourceFile, and any subsequent zip/delete code) are in progress.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 514f85e6-e1a6-4f3c-bd0b-0cc0bcfa736e

📥 Commits

Reviewing files that changed from the base of the PR and between 7a46eea and 0d743ab.

📒 Files selected for processing (2)
  • Ginger/Ginger/Drivers/DriversConfigsEditPages/SeleniumRemoteWebDriverEditPage.xaml.cs
  • Ginger/GingerCoreNETUnitTest/SeleniumDriverTest/GetDriverPathTest.cs

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs (2)

1326-1335: ⚠️ Potential issue | 🟠 Major

Use the browserType argument inside UpdateDriver().

This method now accepts the target browser, but the actual selection and failure reporting still use mBrowserType. If the instance state does not match the requested browser, GetDriverPath(browserType) can update the wrong driver or return "" entirely. That is user-visible now that SeleniumRemoteWebDriverEditPage.xaml.cs:161-165 explicitly calls GetDriverPath(SeleniumDriver.eBrowserType.Chrome).

🛠️ Proposed fix
-                Reporter.ToLog(eLogLevel.INFO, $"Failed to Download latest {mBrowserType} driver. Attempting to Update {mBrowserType} driver to latest using System Proxy Settings....");
+                Reporter.ToLog(eLogLevel.INFO, $"Failed to download latest {browserType} driver. Attempting to update {browserType} driver to latest using system proxy settings....");
                 DriverOptions driverOptions = null;
 
-                driverOptions = mBrowserType switch
+                driverOptions = browserType switch
                 {
                     eBrowserType.Chrome => new ChromeOptions(),
                     eBrowserType.Edge => new EdgeOptions(),
                     eBrowserType.FireFox => new FirefoxOptions(),
                     _ => null
@@
-                    Reporter.ToUser(eUserMsgKey.FailedToDownloadDriver, mBrowserType);
+                    Reporter.ToUser(eUserMsgKey.FailedToDownloadDriver, browserType);
                 }
-                Reporter.ToLog(eLogLevel.ERROR, string.Format(Reporter.UserMsgsPool[eUserMsgKey.FailedToDownloadDriver].Message, mBrowserType), ex);
+                Reporter.ToLog(eLogLevel.ERROR, string.Format(Reporter.UserMsgsPool[eUserMsgKey.FailedToDownloadDriver].Message, browserType), ex);

Also applies to: 1373-1377

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs`
around lines 1326 - 1335, Update the UpdateDriver() implementation to use the
method parameter browserType instead of the instance field mBrowserType: replace
references to mBrowserType in the Reporter.ToLog call and the switch that builds
driverOptions (currently returning ChromeOptions/EdgeOptions/FirefoxOptions) so
they switch on browserType; also update any subsequent similar blocks (around
the second block at lines 1373-1377) to use browserType and ensure calls to
GetDriverPath(browserType) and any error messages reference the passed-in
browserType so the requested browser is updated/logged correctly.

505-511: ⚠️ Potential issue | 🟠 Major

Remove the finalizer and implement a proper IDisposable pattern.

The finalizer ~SeleniumDriver() calls CloseDriver(), which is unsafe for multiple reasons:

  1. It accesses managed state (POMUtils, Driver, BMPClient, BMPServer)
  2. It blocks on async code via StopNetworkLog().GetAwaiter().GetResult() — this can deadlock when called from the finalizer thread
  3. Finalizers are nondeterministic and run on the GC thread, not the main application thread

The class should implement IDisposable with a public Dispose() method for explicit cleanup instead of relying on the finalizer.

Current unsafe code
-        ~SeleniumDriver()
-        {
-            if (Driver != null)
-            {
-                CloseDriver();
-            }
-        }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs`
around lines 505 - 511, Remove the finalizer ~SeleniumDriver() and implement the
standard IDisposable pattern on SeleniumDriver: add a public Dispose() that
calls a protected virtual Dispose(bool disposing), call
GC.SuppressFinalize(this), and move all managed resource cleanup (accessing
POMUtils, Driver, BMPClient, BMPServer) into Dispose(true) so CloseDriver is
invoked deterministically from Dispose rather than a finalizer. Refactor
CloseDriver/StopNetworkLog so Dispose does not block on async code: either
provide an async CloseDriverAsync/StopNetworkLogAsync and implement
IAsyncDisposable (DisposeAsync) to await them, or make CloseDriver perform only
synchronous safe teardown and kick off StopNetworkLog asynchronously without
blocking (e.g., fire-and-forget with proper error handling). Ensure no managed
state is accessed from a finalizer and remove the existing ~SeleniumDriver()
finalizer reference.
♻️ Duplicate comments (1)
Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs (1)

1158-1164: ⚠️ Potential issue | 🔴 Critical

This retry still does not wait for UpdateDriver().

ConfigureAwait(true) only changes how an awaited continuation resumes; because nothing awaits the returned awaitable here, the update runs fire-and-forget and StartDriver() retries immediately. The restart can still happen against the stale driver. The updated UI caller in SeleniumRemoteWebDriverEditPage.xaml.cs:161-165 awaits this API correctly; this path still does not.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs`
around lines 1158 - 1164, The retry path is firing
UpdateDriver(mBrowserType).ConfigureAwait(true) without awaiting it, so
UpdateDriver runs fire-and-forget and StartDriver() runs against the stale
driver; change the method containing the RestartRetry logic to be async and
await the UpdateDriver call (e.g. await
UpdateDriver(mBrowserType).ConfigureAwait(false or true as appropriate) ) before
calling StartDriver(), and remove the unawaited ConfigureAwait usage; update any
callers if necessary to handle the now-async method so the restart truly waits
for UpdateDriver to complete (symbols: RestartRetry, UpdateDriver, StartDriver
in SeleniumDriver).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs`:
- Around line 1326-1335: Update the UpdateDriver() implementation to use the
method parameter browserType instead of the instance field mBrowserType: replace
references to mBrowserType in the Reporter.ToLog call and the switch that builds
driverOptions (currently returning ChromeOptions/EdgeOptions/FirefoxOptions) so
they switch on browserType; also update any subsequent similar blocks (around
the second block at lines 1373-1377) to use browserType and ensure calls to
GetDriverPath(browserType) and any error messages reference the passed-in
browserType so the requested browser is updated/logged correctly.
- Around line 505-511: Remove the finalizer ~SeleniumDriver() and implement the
standard IDisposable pattern on SeleniumDriver: add a public Dispose() that
calls a protected virtual Dispose(bool disposing), call
GC.SuppressFinalize(this), and move all managed resource cleanup (accessing
POMUtils, Driver, BMPClient, BMPServer) into Dispose(true) so CloseDriver is
invoked deterministically from Dispose rather than a finalizer. Refactor
CloseDriver/StopNetworkLog so Dispose does not block on async code: either
provide an async CloseDriverAsync/StopNetworkLogAsync and implement
IAsyncDisposable (DisposeAsync) to await them, or make CloseDriver perform only
synchronous safe teardown and kick off StopNetworkLog asynchronously without
blocking (e.g., fire-and-forget with proper error handling). Ensure no managed
state is accessed from a finalizer and remove the existing ~SeleniumDriver()
finalizer reference.

---

Duplicate comments:
In `@Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs`:
- Around line 1158-1164: The retry path is firing
UpdateDriver(mBrowserType).ConfigureAwait(true) without awaiting it, so
UpdateDriver runs fire-and-forget and StartDriver() runs against the stale
driver; change the method containing the RestartRetry logic to be async and
await the UpdateDriver call (e.g. await
UpdateDriver(mBrowserType).ConfigureAwait(false or true as appropriate) ) before
calling StartDriver(), and remove the unawaited ConfigureAwait usage; update any
callers if necessary to handle the now-async method so the restart truly waits
for UpdateDriver to complete (symbols: RestartRetry, UpdateDriver, StartDriver
in SeleniumDriver).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: fb567737-cf91-4fbb-8c31-a5510d710c5b

📥 Commits

Reviewing files that changed from the base of the PR and between 6836eec and 835dc0b.

📒 Files selected for processing (1)
  • Ginger/GingerCoreNET/Drivers/CoreDrivers/Web/Selenium/SeleniumDriver.cs

@ravirk91 ravirk91 merged commit dea527e into master Mar 11, 2026
20 of 26 checks passed
@ravirk91 ravirk91 deleted the Enhancement/SeleniumUpgrade branch March 11, 2026 12:27
@coderabbitai coderabbitai Bot mentioned this pull request Mar 31, 2026
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