Skip to content

Conversation

@visagang
Copy link
Contributor

@visagang visagang commented Aug 20, 2025

PR Type

Enhancement


Description

  • Add keyboard navigation support for dropdown selection

  • Implement PressKey-based dropdown interaction as alternative to clicking

  • Maintain backward compatibility with existing click-based selection

  • Improve dropdown handling flexibility in web automation


Diagram Walkthrough

flowchart LR
  A["Click Dropdown"] --> B{"PressKey Available?"}
  B -->|Yes| C["Press Key + Enter"]
  B -->|No| D["Locate Option by Text"]
  D --> E["Click Option"]
  C --> F["Selection Complete"]
  E --> F
Loading

File Walkthrough

Relevant files
Enhancement
PlaywrightWebDriver.DoAction.cs
Enhanced dropdown selection with keyboard navigation         

src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.DoAction.cs

  • Add conditional logic to check for PressKey property in dropdown
    actions
  • Implement keyboard navigation using PressKey followed by Enter key
  • Preserve existing text-based option selection as fallback method
  • Restructure dropdown handling logic with proper branching
+14/-6   

@qodo-merge-pro
Copy link

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

Selector Robustness

The XPath //div[text()='...'] is brittle for dropdowns that render options in other tags, nested structures, or with trimmed/whitespace differences. Consider a more resilient selector (e.g., contains(), role-based, or scoping under the opened dropdown container) to avoid false negatives.

var optionLocator = page.Locator($"//div[text()='{action.Content}']");
var optionCount = await optionLocator.CountAsync();
if (optionCount == 0)
{
    Serilog.Log.Error($"Dropdown option not found: {action.Content}");
    return;
}
await optionLocator.First.ClickAsync();
Error Handling

When PressKey is provided, failures from Keyboard.PressAsync or from the dropdown not reacting are not handled. Consider timeouts, waiting for option popup/selection state, or verifying the selection post keypress to ensure reliability.

if (!string.IsNullOrWhiteSpace(action.PressKey))
{
    await page.Keyboard.PressAsync(action.PressKey);
    await page.Keyboard.PressAsync("Enter");
}
else
Localization/Case Sensitivity

Matching option text exactly may fail with case differences, leading/trailing spaces, or localized strings. Consider normalizing text or supporting contains/regex to improve match rates.

var optionLocator = page.Locator($"//div[text()='{action.Content}']");
var optionCount = await optionLocator.CountAsync();
if (optionCount == 0)
{
    Serilog.Log.Error($"Dropdown option not found: {action.Content}");
    return;
}
await optionLocator.First.ClickAsync();

@qodo-merge-pro
Copy link

PR Code Suggestions ✨

Explore these optional code suggestions:

CategorySuggestion                                                                                                                                    Impact
General
Harden option text locator

Make the locator robust against surrounding whitespace and nested text nodes by
using normalize-space() and descendant text matching. This reduces false
negatives when the UI has extra spaces or spans inside options.

src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.DoAction.cs [73-80]

-var optionLocator = page.Locator($"//div[text()='{action.Content}']");
+var optionLocator = page.Locator($"//div[normalize-space(text())='{action.Content}'] | //div[.//text()[normalize-space(.)='{action.Content}']]");
 var optionCount = await optionLocator.CountAsync();
 if (optionCount == 0)
 {
     Serilog.Log.Error($"Dropdown option not found: {action.Content}");
     return;
 }
 await optionLocator.First.ClickAsync();
  • Apply / Chat
Suggestion importance[1-10]: 7

__

Why: This suggestion significantly improves the robustness of the XPath locator by using normalize-space() and checking for descendant text, making the option selection less brittle and less likely to fail due to minor HTML structure or whitespace changes.

Medium
Wait for dropdown to render

Add a short wait for the dropdown panel to render after the click before
proceeding with key presses or option selection. This prevents race conditions
where actions run before the menu is present.

src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.DoAction.cs [65-81]

 await locator.ClickAsync();
+// Allow dropdown to render
+await page.WaitForTimeoutAsync(100);
 if (!string.IsNullOrWhiteSpace(action.PressKey))
 {
     await page.Keyboard.PressAsync(action.PressKey);
     await page.Keyboard.PressAsync("Enter");
 }
 else
 {
-    var optionLocator = page.Locator($"//div[text()='{action.Content}']");
+    var optionLocator = page.Locator($"//div[normalize-space(text())='{action.Content}'] | //div[.//text()[normalize-space(.)='{action.Content}']]");
     var optionCount = await optionLocator.CountAsync();
     if (optionCount == 0)
     {
         Serilog.Log.Error($"Dropdown option not found: {action.Content}");
         return;
     }
     await optionLocator.First.ClickAsync();
 }
  • Apply / Chat
Suggestion importance[1-10]: 6

__

Why: The suggestion correctly points out a potential race condition where actions are performed before the dropdown menu appears. Adding a wait after the click is a good practice to improve the reliability of the UI interaction.

Low
Possible issue
Focus element before key presses

Ensure the dropdown is focused before sending keyboard events to avoid keys
going to the wrong element. Also add a short wait for the dropdown options panel
to appear to improve reliability on slower UIs.

src/Plugins/BotSharp.Plugin.WebDriver/Drivers/PlaywrightDriver/PlaywrightWebDriver.DoAction.cs [66-70]

 if (!string.IsNullOrWhiteSpace(action.PressKey))
 {
+    // Ensure focus is on the opened dropdown
+    await locator.First.FocusAsync();
+    // Optional: wait for options popup to appear if the UI renders it
+    await page.WaitForTimeoutAsync(100); // small stabilization delay
     await page.Keyboard.PressAsync(action.PressKey);
     await page.Keyboard.PressAsync("Enter");
 }
  • Apply / Chat
Suggestion importance[1-10]: 6

__

Why: The suggestion correctly identifies a potential issue where keyboard events might be sent before the element is focused, and adding FocusAsync and a short wait can improve the automation's reliability.

Low
  • More

@Oceania2018 Oceania2018 merged commit 34f04e7 into SciSharp:master Aug 20, 2025
4 checks passed
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.

3 participants