Using Selenium I need to validate that an element, as it is dragged across the window, will trigger a \'drop zone\' and then release that element in the zone. I can drag the el
It took awhile, but I finally figure out how to watch with MutationObservers. However, I have yet to apply it to a 'drag and drop'.
Once I know which node I need to watch for a change, in most cases if a node is added or removed, I can inject a MutationObserver. I ended up creating a class for all my MO work.
namespace Framework.Utilities
{
public class Watcher
{
private static IWebDriver _driver;
public Watcher(Driver driver) { this.driver = driver; }
public void WatchBody() {
var mutationObserverScript = @”(function (){
var myObserver = window.document.MutationObserver || {};
window.myObserver = {
observer: new MutationObserver(function (mutationsList) {
for (let mutation of mutationsList) {
if (mutation.addedNodes.length >= 1) {
myObserver.occured = true;
myObserver.observer.disconnect();
}
}
}),
occurred: false
};
var config = {childList: true};
var element = document.querySelector(‘boy’);
window. myObserver.observer.observe(element, config);});";
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript(mutationObserverScript);
}
public bool WaitForChange()
{
var results = defaultWait.Until( driver1 => ((IJavaScriptExecutor)_driver).ExecuteScript("returnwindow.myObserver.occurred;").Equals(true));
return results;
}
public bool AffectWith(Action watcher, Action action)
{
watcher();
action();
return WaitForChange();
}
}
}
Some of the above will look familiar. I pulled in various pieces from a variety of postings on the internet.
My use case is watching for an overlay modal to appear:
Instantiate the Watcher class
var watcher = new Watcher(driver);
Setup the action
var myBtn = driver.FindElement(By.CssSelector(buttonSelector));
Action clickButton = () => myBtn.Click();
Observe for the change
if(watcher.AffectWith(watcher.WatchBody, clickButton))
{
<detected modal is gone, keep testing>
}
else
{
<problems with modal>
}
From what I've read, they work well since MutationObservers are executed the same as a ‘Promise’, they are a microtask and are executed before the next task in the DOM. By watching for the ‘flip to true’, I also know that any ‘async’ Microtask Angular call has completed as well.
Of note, disconnecting an observer will not remove it, a good practice it to set it to null. And, by including the ‘{}’ when defining the MutationObserver, you can index it. This prevents multiple MutationObservers from resetting parameters while another one is still active.