Добрый день.
Как можно отследить изменение текста на странице с помощью Selenium + Java после выполнения AJAX?
Т.е. например был локатор с текстом “Text 1” -> далее AJAX -> далее в этом локаторе “Text 2”.
Спасибо
Добрый день.
Как можно отследить изменение текста на странице с помощью Selenium + Java после выполнения AJAX?
Т.е. например был локатор с текстом “Text 1” -> далее AJAX -> далее в этом локаторе “Text 2”.
Спасибо
Кастомные ExpectedConditions
- стандартная практика для таких случаев. Вам нужен вариант - обратный textToBePresentInElementLocated:
public void textChanged(final By locator) {
final String currentText = getText(locator);
wait.until((WebDriver driver) -> !getText(locator).equals(currentText));
}
Note: getText
- обертка над страндартным API.
Если нужно возвращать true / false, хэндлите exception:
public boolean textChanged(final By locator) {
final String currentText = getText(locator);
return Try.run(() -> wait.until((WebDriver driver) -> !getText(locator).equals(currentText)))
.isSuccess();
}
Note: Try
- functional style замена стандартному try / catch
из библиотеки javaslang.
круто! Спасибо ))
компилятор ругается на getText() - не известная ф-ция. Что нужно подключить?
driver.findElement(locator).getText();
Хм… Неужели никто не скажет?
Selenide же идеально для этого подходит!
$("div").shouldHave(text("Text 1"));
$("button").click();
$("div").shouldHave(text("Text 2"));
И всё! Вот так просто. Никаких тебе ожиланий, никаких лямбд, никаких слипов и циклов.
Исходя из предложенной формулировки, речь шла о динамическом изменении текста. Ни о каких промежуточных действиях (по типу клика) никто ничего не говорил. Банальный пример - изменение статуса загрузки файла: uploading -> validating -> done. Напишите пример на Selenide, как вы будете отслеживать текст динамически изменяемой лейблы без ожиданий, лямбд и прочего. Или сам факт изменения текста, когда не нужно ничего асертить, а лишь понять, что можно продолжать дальнейшее взаимодействие со страницей.
@ArtOfLife Ну нет, там было очень чётко сказано, что текст известен:
был локатор с текстом “Text 1” -> далее AJAX -> далее в этом локаторе “Text 2”.
Впрочем, неважно. Без действий его можно точно так же проверить:
$("div").shouldHave(text("Text 1"));
$("div").shouldHave(text("Text 2"));
Правда, без действий (как бы его ни написать) этот тест потенциально ненадёжный, потому что рано или поздно случится, что Ajax отработает раньше, чем первая строка теста, и тест завалится.
А если даже точные тексты неизвестны и хочется проверить только сам факт изменения текста, можно, например, так:
String initialText = $("div").text();
$("div").shouldNotHave(text(initialText));
Впрочем, и этот тест потенциально ненадёжный по той же причине.
Поэтому лучше всё-таки точно знать, как должно вести себя тестируемое приложение. Иначе это не тестирование, а танцы с бубном.
Отследить != верифицировать. В данном условии нам не нужно проверять конкретный текст. Нам нужно узнать, а не изменился ли исходный.
Последний пример ближе к истине. Но вот если мне нужно будет задать определенный интервал ожидания, да еще и хэндлить потенциальный exception, ваш код обрастет все теми же вейтами и try / catch, разве нет?
Да, пожалуй что обрастёт.
Но просто не надо этого делать, во вселенной и без этого полно зла.
Зачем в строке
wait.until((WebDriver driver) -> !getText(locator).equals(currentText));
указывать “(WebDriver driver) ->”? Почему нельзя просто написать
wait.until(!getText(locator).equals(currentText));
Проверял и знаю, что будет ошибка. Не понятно, почему? Это стандарт такой для всех кастомных wait’оров?
В случае, например, если необходимо дождаться, пока bar не будет больше 5, то код будет выглядеть так:
wait.until((WebDriver driver) -> bar>5);
?
Потому что результат вашего условия - boolean
, а метод until
принимает один из следующих функциональных интерфейсов:
Function
тут само собой не подойдет, ибо она должна возвращать WebElement
, т.е. остается Predicate
, который на вход принимает драйвер, а возвращает boolean
. Технически вам никто не запрещает игнорировать input аргументы. Тут важно, чтобы лямбда соответствовала определению абстрактного метода требуемого функционального интерфейса.
Подробнее о механике работы лямбд, и их взаимосвязи с функциональными интерфейсами, можете посмотреть тут:
П.С. Хотя, в селениуме заложены гуавовские интерфейсы, суть от этого не меняется.