Tutorials

Tutorials

Driving Native Dropdowns with SelectClick

Native HTML select elements don't behave like ordinary clickable elements. SelectClick gives GPAL a vocabulary for them - left-click an option, jump to the next or previous option, wrap around at the ends, or pick at random - and WithHardware drives the dropdown the way a real user would, with actual OS-level input.

Complete Program

This example targets a native select element on a category-navigation menu, then runs through the SelectClick vocabulary: an initial left-click on a known option, a random pick, stepping to the next and previous options, and wrapping around at the top and bottom of the list.

using GenerallyPositive;

using GenerallyPositive.Browser;

using static GenerallyPositive.Enums;

Selector categorySelector = GPAL.Selector

.WithCSS("#category-menu > option:nth-child(36)")

.WithHardware

.WithSelectorName("Category Menu Option")

.ToGPALObject();

GPAL

.WithAutoUpdateWebDriver();

IBrowser browser = GPAL.Browser

.WithBrowserType(BrowserType.Chrome)

.WithDriverLocation(@"c:drivers")

.ToGPALObject();

browser.GoTo("https://www.example-shop.com/");

browser

.WithSelector(categorySelector)

.SelectClick(SelectClickType.LeftClick)

.WaitFor(5_000);

browser

.SelectClick(SelectClickType.SelectRandom)

.WaitFor(5_000);

browser

.SelectClick(SelectClickType.SelectNext)

.WaitFor(5_000);

browser

.SelectClick(SelectClickType.SelectPrevious)

.WaitFor(5_000);

browser

.LeftClick(categorySelector)

.WaitFor(5_000)

.SelectClick(SelectClickType.SelectNextWithWrap)

.WaitFor(5_000)

.SelectClick(SelectClickType.SelectPreviousWithWrap)

.WaitFor(5_000);

browser.Close(true);

Hardware-Level Selectors for Native Controls

WithHardware tells GPAL to interact with this element through OS-level input (real mouse and keyboard events) rather than Selenium's normal element interaction. Native select dropdowns render their open option list outside the regular DOM in many browsers, so Selenium and JavaScript-based clicks can report success while the visible menu doesn't actually change - hardware interaction matches what a real user does and reliably opens and changes the selection.

Selector categorySelector = GPAL.Selector

.WithCSS("#category-menu > option:nth-child(36)")

.WithHardware

.WithSelectorName("Category Menu Option")

.ToGPALObject();

TIP

With a native select, Selenium and JavaScript clicks may report the option as selected internally without the on-screen menu reflecting it, while hardware emulation reflects exactly what a user would see. When a select interaction looks like it worked but the page doesn't react, try WithHardware.

LeftClick Opens the Menu and Picks the Option

The first SelectClick(SelectClickType.LeftClick) opens the dropdown and clicks the targeted option, just like a user clicking the menu and then clicking an entry. WaitFor afterward gives the page time to react to the navigation that follows.

browser

.WithSelector(categorySelector)

.SelectClick(SelectClickType.LeftClick)

.WaitFor(5_000);

Stepping Through Options: Random, Next, Previous

Once a select element is the active selector, further SelectClick calls reuse it. SelectRandom picks any option in the list; SelectNext and SelectPrevious move one option at a time relative to whatever is currently selected.

browser

.SelectClick(SelectClickType.SelectRandom)

.WaitFor(5_000);

browser

.SelectClick(SelectClickType.SelectNext)

.WaitFor(5_000);

browser

.SelectClick(SelectClickType.SelectPrevious)

.WaitFor(5_000);

Wrapping Around the Ends of the List

SelectNextWithWrap and SelectPreviousWithWrap behave like SelectNext and SelectPrevious, except that stepping past the last option wraps to the first, and stepping before the first wraps to the last. LeftClick(categorySelector) re-establishes a known starting option before the wrap demonstration.

browser

.LeftClick(categorySelector)

.WaitFor(5_000)

.SelectClick(SelectClickType.SelectNextWithWrap)

.WaitFor(5_000)

.SelectClick(SelectClickType.SelectPreviousWithWrap)

.WaitFor(5_000);

browser.Close(true);

WARNING

Passing true kills the running web driver process. The actual test program in the repo loops over every BrowserType, AutomationEngine, and headless/headful combination for regression purposes (see Automation Engines) - in real workflows you only need the single pass shown here.