DragAndDrop performs a hardware-level drag from one element to another, using offsets and deltas to land precisely. This tutorial walks through closing a popup with LeftClick and then dragging a map element using a selector built from CSS, XPath, text, an image, and pixel offsets.
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;
static Selector closeButtonSelector = (Selector)GPAL.Selector
.WithCSS(@"#dialog > div > button")
.WithXPath(@"//*[@id="dialog"]/div/button")
.WithText(@"x")
.MatchText(@"x")
.WithOffsetX(26)
.WithOffsetY(18)
.WithImage(imageData);
static Selector mapSelector = (Selector)GPAL.Selector
.WithCSS(@"#map")
.WithXPath(@"//*[@id="map"]")
.WithText(@"A pretty popup. Easily customizable.")
.MatchText(@"A pretty popup. Easily customizable.")
.WithOffsetX(694)
.WithOffsetY(109)
.WithDeltaX(-524)
.WithDeltaY(3);
IBrowser browser = GPAL.Browser
.WithBrowserType(BrowserType.Chrome)
.WithLoadImages(true)
.WithBlockPopUps(true)
.WithDriverLocation(@"C:drivers")
.WithUseAutomationEngine(AutomationEngine.PuppeteerPort)
.GoTo("https://example-maps.com/")
.ToGPALObject();
browser
.LeftClick(closeButtonSelector);
browser
.DragAndDrop(mapSelector);
browser.Close(true);
closeButtonSelector stacks CSS, XPath, expected text (both WithText and MatchText), and a reference image (WithImage) all on the same selector. GPAL doesn't require you to pick just one strategy - it can use whichever combination of clues is available to find and confirm the element. WithOffsetX and WithOffsetY then say exactly where, relative to that element, the click should land.
static Selector closeButtonSelector = (Selector)GPAL.Selector
.WithCSS(@"#dialog > div > button")
.WithXPath(@"//*[@id="dialog"]/div/button")
.WithText(@"x")
.MatchText(@"x")
.WithOffsetX(26)
.WithOffsetY(18)
.WithImage(imageData);
WithImage takes image data (here, captured ahead of time as a base64 string in a field called imageData) that GPAL can use to visually confirm or locate the element on screen. This is most useful when CSS and XPath alone aren't reliable, such as canvas-based UI or elements that shift position. See The Selector System.
Before dragging anything, the workflow left-clicks the popup's close button. This is a normal LeftClick - no different from clicking any other element - it just happens to be the cleanup step that needs to run before the map underneath is usable.
browser
.LeftClick(closeButtonSelector);
mapSelector defines a starting point on the map (via WithOffsetX/WithOffsetY, relative to the matched element) and a movement distance (WithDeltaX/WithDeltaY - here, moving left 524 pixels and down 3 pixels). DragAndDrop performs a press-move-release sequence from the starting point across that delta, simulating a real mouse drag.
static Selector mapSelector = (Selector)GPAL.Selector
.WithCSS(@"#map")
.WithXPath(@"//*[@id="map"]")
.WithOffsetX(694)
.WithOffsetY(109)
.WithDeltaX(-524)
.WithDeltaY(3);
browser
.DragAndDrop(mapSelector);
Drag-and-drop performed at the hardware level moves the real mouse cursor and requires the browser window to have focus and be in front. If another window steals focus mid-drag, the drag can land in the wrong place or fail entirely. See Hardware-Level Interaction.
The actual test program in the repo loops over every BrowserType, AutomationEngine, and headless/headful combination, running this same close-then-drag sequence each time. That's purely for regression coverage across engines - your own workflow only needs the single pass shown above. See Automation Engines for what each engine offers.
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();