Пытаюсь реализовать кастомное условие на ожидание изменения списка потомков в DOM. Проблема в том, что размер этого списка может остаться прежним, при этом элементы могут обновиться. У меня есть окно выбора элементов, элементы которого я фильтрую при помощи строки поиска. После ввода строки в input, я хочу быть уверен, что список элементов был изменен.
Я не смог найти готовое решение среди Conditions в selenide, поэтому решил прибегнуть к исполнению js в рамках теста. Я попытался подключить MutationObserver, который бы отслеживал изменения в родительской ноде для этих элементов, но я не уверен в таком случае, что объект наблюдателя создаться до заполнения строки фильтра из за асинхронности.
Каким образом можно отслеживать изменения в DOM после заполнения строки фильтра?
Код:
Класс с кастомным условием
public IsElementChanged(){
super("IsElementChanged");
}
@CheckReturnValue
public @NotNull CheckResult check(Driver driver, WebElement element) {
String script =
"var callback = arguments[arguments.length - 1];" +
"function elementChanged(arguments[0]) {\n" +
" return new Promise((resolve) => { \n" +
" new MutationObserver((mutationsList, observer) => {\n" +
" if (mutationsList.length > 0) {\n" +
" resolve();\n" +
" observer.disconnect();\n" +
" }\n" +
"\n" +
" })\n" +
" .observe(targetNode, {subtree: true, childList: true});\n" +
" });\n" +
"};\n" +
"elementChanged(targetNode).then(() => { return callback(true); })";
Object isElementChanged = null;
try {
isElementChanged = executeAsyncJavaScript(script, element);
}
catch (Exception e){
e.printStackTrace();
}
boolean result = isElementChanged != null && (boolean) isElementChanged;
String actualValue = String.format("isElementChanged:%s", result);
return new CheckResult(result ? CheckResult.Verdict.ACCEPT : CheckResult.Verdict.REJECT, actualValue);
}
@CheckReturnValue
@Nonnull
public Condition negate() {
return new Not(this, true);
}
}
Вызов этого условия:
/**
* Метод осуществляет фильтрацию строк по тексту в столбце
* @param searchStr строка поиска для фильтра
* @param columnName название столбца
*/
private void filterForColumn(String searchStr, String columnName) {
// Xpath для фильтра конкретного столбца в таблице
final String columnFilterInputXpathString = headerFilterRowXpathString +
"//td[contains(@aria-label,'" +
columnName +
"')]" +
"//input";
final By columnFilterInputLocator = By.xpath(columnFilterInputXpathString);
$(columnFilterInputLocator)
.shouldBe(Condition.visible)
.should(ajaxFinished)
.clear();
$(columnFilterInputLocator)
.shouldBe(Condition.visible)
.should(ajaxFinished)
.sendKeys(searchStr);
$(By.xpath(contentXpathString))
**.should(isElementChanged)**
.should(ajaxFinished);
}
Selenide 6.0.3