Standard HTML <select> dropdowns render as OS-level popups that scripted clicks often can't reach. This tutorial shows how to target an <option> with a hardware-emulated selector and use SelectClick to choose it directly or step through the list - next, previous, random, and wrap-around.
Here's the whole workflow, start to finish. Each piece is broken down and explained below.
using GenerallyPositive;
using GenerallyPositive.Browser;
using static GenerallyPositive.Enums;
GPAL
.WithUseOttoMagic(@"C:OttoMagic")
.WithAutoUpdateWebDriver();
// the last <option> in eBay's category <select> - "Everything Else"
Selector categoryOption = GPAL.Selector
.WithCSS("#gh-cat > option:nth-child(36)")
.WithHardware
.ToGPALObject();
IBrowser browser = GPAL.Browser
.WithBrowserType(BrowserType.Chrome)
.WithDriverLocation(@"c:drivers")
.WithUseAutomationEngine(AutomationEngine.OttoMagic)
.GoTo("https://www.ebay.com/")
.ToGPALObject();
browser
.WithSelector(categoryOption)
.SelectClick(SelectClickType.LeftClick) // jump straight to "Everything Else" (the last option)
.WaitFor(5_000)
.SelectClick(SelectClickType.SelectRandom) // pick a random category
.WaitFor(5_000)
.SelectClick(SelectClickType.SelectNext) // move to the next option
.WaitFor(5_000)
.SelectClick(SelectClickType.SelectPrevious) // back to the previous option
.WaitFor(5_000)
.LeftClick(categoryOption) // re-select "Everything Else" so we know exactly where we are
.WaitFor(5_000)
.SelectClick(SelectClickType.SelectNextWithWrap) // already on the last option, so this wraps to the first ("All")
.WaitFor(5_000)
.SelectClick(SelectClickType.SelectPreviousWithWrap) // wrap back down to the last option ("Everything Else")
.WaitFor(5_000)
.Close(true);
We point a Selector at one specific <option> inside eBay's category dropdown - the last entry, "Everything Else" - using a plain CSS path. SelectClick can then operate on that <option> regardless of how the click is actually carried out under the hood.
// the last <option> in eBay's category <select> - "Everything Else"
Selector categoryOption = GPAL.Selector
.WithCSS("#gh-cat > option:nth-child(36)")
.WithHardware
.ToGPALObject();
Every automation engine has its own technique for working with a <select> menu - this isn't something only WithHardware can do. The hardware approach used here works by scrolling through the real OS popup from the top of the list down to the target option, which is reliable but a little tedious. Try removing WithHardware and re-running with a different engine to see its native approach instead.
Same pattern as every other GPAL workflow: pick a browser type and automation engine, then GoTo a URL. SelectClick works the same way regardless of which engine is driving the page underneath.
IBrowser browser = GPAL.Browser
.WithBrowserType(BrowserType.Chrome)
.WithDriverLocation(@"c:drivers")
.WithUseAutomationEngine(AutomationEngine.OttoMagic)
.GoTo("https://www.ebay.com/")
.ToGPALObject();
Swapping AutomationEngine.OttoMagic for Selenium, PuppeteerPort, or any other engine doesn't change anything below this line. See Automation Engines.
WithSelector points GPAL at the <option> we defined earlier, and SelectClick(LeftClick) opens the dropdown and chooses that exact entry - the same result as a user clicking it by hand. SelectClick understands it's working with a <select> menu, so it handles opening the popup and making the choice in one call.
browser
.WithSelector(categoryOption)
.SelectClick(SelectClickType.LeftClick) // jump straight to "Everything Else"
.WaitFor(5_000)
After the first SelectClick, GPAL knows which <select> and which option are active - so the chain can keep calling SelectClick with SelectRandom, SelectNext, and SelectPrevious to move around the list relative to the current choice, without specifying WithSelector again. Before testing the wrap-around variants, we use LeftClick to jump back to "Everything Else" - the last option in the list - so we know exactly where we're starting from. From there, SelectNextWithWrap has nowhere to go but back to the first option ("All"), and SelectPreviousWithWrap from "All" wraps back down to "Everything Else".
.SelectClick(SelectClickType.SelectRandom) // pick a random category
.WaitFor(5_000)
.SelectClick(SelectClickType.SelectNext) // move to the next option
.WaitFor(5_000)
.SelectClick(SelectClickType.SelectPrevious) // back to the previous option
.WaitFor(5_000)
.LeftClick(categoryOption) // re-select "Everything Else" so we know exactly where we are
.WaitFor(5_000)
.SelectClick(SelectClickType.SelectNextWithWrap) // already on the last option, so this wraps to the first ("All")
.WaitFor(5_000)
.SelectClick(SelectClickType.SelectPreviousWithWrap) // wrap back down to the last option ("Everything Else")
.WaitFor(5_000)
.Close(true);
Repeated SelectClick and LeftClick calls reuse the selector and unit of work from the most recent WithSelector. That's why LeftClick(categoryOption) above can reset the menu to a known position without calling WithSelector again - but if your next step needs to act on a different element, call WithSelector again to make that explicit.
Showing off some plain text in these paragraphs eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Lorem ipsum dolor sit amet consectetur adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Lorem ipsum dolor sit amet consectetur adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quo veniam mollitia excepturi animi eum illum non libero sapiente provident assumenda, delectus voluptatum nobis sed dolorem adipisci laudantium incidunt. Error, ratione?
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quo veniam mollitia excepturi animi eum illum non libero sapiente provident assumenda, delectus voluptatum nobis sed dolorem adipisci laudantium incidunt. Error, ratione?
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quo veniam mollitia excepturi animi eum illum non libero sapiente provident assumenda, delectus voluptatum nobis sed dolorem adipisci laudantium incidunt. Error, ratione?
Lorem ipsum dolor sit amet consectetur adipisicing elit. Quo veniam mollitia excepturi animi eum illum non libero sapiente provident assumenda, delectus voluptatum nobis sed dolorem adipisci laudantium incidunt. Error, ratione?
Here you can find different accents and emphasis sit amet consectetur adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
This is a link and how it could look like bestlinkinthebeautifulworld. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Here's just some classic bold text adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam notBoldSecondbestlinkinthebeautifulworld illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Obcaecati, iste distinctio veritatis eligendi laboriosam adipisicing elit illo nostrum corporis at adipisicing elit libero vel voluptas? Expedita, adipisicing facere dolores voluptatem ad ab rem assumenda soluta!
Other cuple of colors in case we want to emphasize several ways adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam adipisicing elit illo nostrum corporis at voluptatem libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Lorem ipsum dolor sit amet consectetur adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta! Lorem ipsum dolor, sit amet consectetur adipisicing elit. Quod veniam, quam ad expedita laborum sed at voluptates culpa ipsam ut vel. Ullam temporibus a mollitia quod aliquam ratione exercitationem nesciunt.
Lorem ipsum dolor sit amet consectetur adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta! Lorem ipsum dolor, sit amet consectetur adipisicing elit. Quod veniam, quam ad expedita laborum sed at voluptates culpa ipsam ut vel. Ullam temporibus a mollitia quod aliquam ratione exercitationem nesciunt.
Lorem ipsum dolor sit amet consectetur adipisicing elit. Obcaecati, iste distinctio veritatis eligendi laboriosam illo nostrum corporis at libero vel voluptas? Expedita, facere dolores voluptatem ad ab rem assumenda soluta!
Lorem ipsum dolor sit amet consectetur adipisicing elit. Repudiandae quas consequuntur illo numquam assumenda autem exercitationem distinctio perspiciatis in natus. Eius dicta similique ipsam ipsa minima, nemo quae enim tempore.
GPAL
.CallIfNotFound(GenericCallIfNotFound)
.WithPublishToConsole();
//System.Drawing.Rectangle windowSize = new System.Drawing.Rectangle(10, 10, 1500, 1024);
// NOTE: we have to set browser = before we execute any steps
// this is due to the 'GenericCallIfNotFound' which might throw an exception, and BankScraper will not have the browser set when it calls scraper.Close()
// until the complete fluent line gets executed (meaning every step, meaning browser is not set until everything else succeeds)
browser = GPAL.Browser
.WithBrowserType(Enums.BrowserType.Chrome)
.WithProfileDataDirectory(ChromeProfileLocation)
.WithUseAutomationEngine(AutomationEngine.Selenium)
.WithWindowSize(new System.Drawing.Rectangle(0,0,1920,1080))
.ToGPALObject();