Явные и неявные ожидания - помогите разобраться

Помогите пожалуйста разобраться в вопросе явных и неявных ожиданий.

После просмотра лекций, я понял (но пока как-то не до конца :pensive: ) что лучше использовать явные ожидания, через WebDriverWait. В тоже время для этого нужно отключить неявные, имплицитные ожидания.

1 вопрос: правильно ли я понял, что их нужно отключать (ставить на 0)?

2 вопрос: как теперь (после отключения) работает поиск элементов на страницах, например в таком виде:

    @FindBy(id = "logOutButton")
    private WebElement logoutButton;

3 вопрос: в менеджере страниц, есть метод инициализации элементов, в котором снова есть какие-то ожидания (10 секунд):

    private <T extends BasicPage> T initElements(T page) {
    	PageFactory.initElements(new AjaxElementLocatorFactory(webDriver, 10), page);		
    	
    	return page;
    }

Что это за 10 секунд? Это тоже относится к ожиданиям?

4 вопрос: как вообще работает поиск и ожидания для страниц? Вот для примера к этой:

    public class DashboardPage extends BasicPage {
    
        	@FindBy(id = "logOutButton")
        	private WebElement logoutButton;
        	
        	public DashboardPage(ApplicationManager appManager) {
        		super(appManager);
        	}	
        	
        	public DashboardPage clickLogoutButton() {
        		logoutButton.click();	
        		return this;		
        	}		
        
        }

В этом случае поиск элемента будет осуществляться при выполнении метода clickLogoutButton? Или в какой момент? И с каким ожиданием?

Прошу прощения за множество вопросов, но я был бы рад, если вы мне поможете уяснить эту тему. Буду очень благодарен за помощь!

По умолчанию емнип и так 0 .
неявные это для webdriver.findElement/Elements .
сколько ждет появления елемента в Dom. емнип опрос каждые 500 ms

2 / 3 /4 ) @FindBy и далее.

ExplanationThe PageFactory
relies on using sensible defaults: the name of the field in the Java
class is assumed to be the “id” or “name” of the element on the HTML
page. That is, in the example above, the line: q.sendKeys(text);is equivalent to: driver.findElement(By.id(“q”)).sendKeys(text);
https://code.google.com/p/selenium/wiki/PageFactory

по
PageFactory.initElements(new AjaxElementLocatorFactory(webDriver, 10), page);

2 лайка

ExplanationThe PageFactory
relies on using sensible defaults: the name of the field in the Java
class is assumed to be the “id” or “name” of the element on the HTML
page. That is, in the example above, the line: q.sendKeys(text);is equivalent to: driver.findElement(By.id(“q”)).sendKeys(text);
GitHub - SeleniumHQ/selenium-google-code-issue-archive: Archive, please see main selenium repo

Кажется начинаю понимать - то есть, если я отключил неявные ожидания, то на каждой странице нужно реализовать какой-то метод, в котором уже явным ожиданием появления какого-то элемента нужно убедиться что страница загружена. Только после этого уже оперировать другими элементами.

Метод вроде такого:

  public DashboardPage pageIsLoaded() {
    wait.until(presenceOfElementLocated(By.id("logOutButton")));
    return this;
  }

Правильно я понимаю?

Скорее правильнее будет в методах, где ты используешь явные ожидания добавить условие что если приходящий таймаут ну к примеру меньше 2-х секунд то ты делаешь Implicity wait в 500 миллисекунд, а после выполнения возвращаешь в дефолтные ну к примеру 5, 20… А пейджам такие тонкости вообще знать не нужно.

1 лайк
Кажется начинаю понимать - то есть, если я отключил неявные ожидания, то на каждой странице нужно реализовать какой-то метод

ты их не отключаешь .Если стоит ты говоришь проверить DOM если этот єлемент прям сейчас .
если ставишь время он ждет периодичски проверяя не появился ли.

1 лайк

Ребята, что-то совсем запутался - так стоит ли вообще устанавливать в 0/оставлять по умолчанию неявные ожидания?

Скорее правильнее будет в методах, где ты используешь явные ожидания добавить условие что если приходящий таймаут ну к примеру меньше 2-х секунд то ты делаешь Implicity wait в 500 миллисекунд, а после выполнения возвращаешь в дефолтные ну к примеру 5, 20… А пейджам такие тонкости вообще знать не нужно.

Не очень понял, можно поподробнее и с примером?
Я планировал установить неявные нулю и пользоваться только явными, а тут получается комбинированный способ. К тому же прочитал тут Руководство пользователя

По умолчанию значение равно 0. Будучи однажды установлено, значение неявного ожидания останется действительным на протяжении всего существования экземпляра объекта “WebDriver”.

Тогда каким образом менять установленные 500 мс на дефолтные? :confused:

Вот такой вот пример. Специально написал все в одном методе, но лучше разделить на 2.
Проверь как работает без изменения implicityWait и как с ним… на примерах глобального implicityWait в 10 секунд и таймаута в метод допустим 2 секунды, при условии что элемент невидим.
Где берется драйвер тоже не важно :smile:

public static boolean isElementVisible(WebElement webElement, int timeOut) {
	boolean isElementVisible = false;
	WebDriverWait wait = new WebDriverWait(driver, timeOut);
	if (timeOut < DEFAULT_TIMEOUT || timeOut < 2){
		driver.manage().timeouts().implicitlyWait(500, TimeUnit.MILLISECONDS);
	}		  
	try {
		wait.until(ExpectedConditions.visibilityOf(webElement));
		isElementVisible =  true;
	} finally {
		driver.manage().timeouts()
                      .implicitlyWait(DEFAULT_TIMEOUT, TimeUnit.SECONDS);
	}
	return isElementVisible;
}

Да кстати если поставишь в ноль implicityWait то получишь ситуацию когда элементы через driver.findElement() и аннотация будут искаться вообще без задержек и будешь получать очень много падений с NoSuchElementException

Все-таки так и остался вопросы:

1. Нужно ставить на 0 неявные ожидания для использования WebDriverWait?

2. Если неявные ожидания = 0, а при инициализации страниц делается

 PageFactory.initElements(new AjaxElementLocatorFactory(driver, 30), this);

То при обращении к элементу страницы будет использовано ожидание 30, а не 0? Так ведь?

1 лайк

Ооо, большое спасибо за ответ и отдельное спасибо за ссылку на обсуждение!

Вот что полезного для себя узнал:

  1. Время неявного ожидания по дефолту = 0, так что можно это не указывать (но я наверное укажу для наглядности),
  2. При обращении к элементу через страницу на самом деле выполняется driver.findElement,
  3. Соответственно если время неявных ожиданий = 0, то ждать появления при findElement не будет,
  4. Но если при инициализации страниц использовать AjaxElementLocatorFactory, то при обращении к элементу через страницу каждые 250 мс на протяжении N секунд указанных в конструкторе будет проверяться наличие элемента (командой findElement). В свою очередь findElement ждет N секунд, установленных в implicitlyWait. А если установлено 0, то и ждать не будет.

Прошу поправьте меня, если я где-то неправильно написал :relieved:


Теперь осталось уяснить на счет зависимости WebDriverWait и времени в implicitlyWait. Работает ли это так же (по аналогии) как и AjaxElementLocatorFactory? Т.е. если допустим implicitlyWait = 10 секунд, то при ожидании через WebDriverWait будет что-то подобное:

  1. Один раз в 500 мс WebDriverWait вызывает findElement,

  2. findElement в свою очередь 10 секунд ждет появления элемента, а
    затем, если его не нашел, отваливается с NoSuchElementException,

  3. Но так как в WebDriverWait игнорируется такое исключение, после
    этого, через 500 мс он снова ищет элемент, используя findElement

Так ли это? :blush:

Так. Причем если в WebDriverWait сетнуть таймаут 2 секунды, по факту будет ждать 10 секунд и будет только один запрос к драйверу на findElement.

1 лайк

Да и по большому счету тебе без разницы сколько тех миллисекунд будет в implicityWait все равно в методы с ожиданиями обычно передаются секунды (а то свихнуться можно), главное чтобы implicityWait при поиске через явные ожидания был меньше чем WebDriverWait, а при поиске обычными ожиданиями его хватало чтобы точно найти элементы.

А зачем мне тогда искать неявными ожиданиями? Я лучше установлю их в 0 и при поиске буду искать с явным ожиданием, через webdriverwait. Поиск элементов на странице будет искаться через AjaxElementLocatorFactory, что по сути тот же webdriverwait.

Или могут быть какие-то случаи когда мне понадобится искать обязательно неявными ожиданиями?

Имхо, это имеет смысл, в случае, если неявные ожидания решают проблему целиком или в подавляющем большинстве случаев, для тестирования данного приложения. Если же все равно приходится прибегать к явным ожиданиям, то лучше сделать удобный механизм для их использования и отказаться от неявных ожиданий

1 лайк

Просто не трогать их, по умолчанию они отключены

Ответ на вопросы 2, 3, 4:
Если при инициализации элементов используется AjaxElementLocator, то при обращении к полям класса страницы WebDriver будет ожидать появления в DOM данного элемента в течение указанного при инициализации времени (в твоем примере 10 сек). Если находит раньше, сразу обращается к нему. Поиск происходит в момент обращения к полю класса страницы

2 лайка
Тогда каким образом менять установленные 500 мс на дефолтные? confused
Ответить в новой связанной теме

Можно . Есть еще такое ожидание Fluent

Waiting 30 seconds for an element to be present on the page, checking

   // for its presence once every 5 seconds.
   Wait<WebDriver> wait = new FluentWait<WebDriver>(driver)
       .withTimeout(30, SECONDS)
       .pollingEvery(5, SECONDS)
       .ignoring(NoSuchElementException.class);

   WebElement foo = wait.until(new Function<WebDriver, WebElement>() {
     public WebElement apply(WebDriver driver) {
       return driver.findElement(By.id("foo"));
     }
   });

но зачем ? :grinning:

1 лайк

Всем большое спасибо за помощь! Всё стало намного понятнее. Надеюсь эта тема будет полезна не только мне, но и другим людям, столкнувшимся с вопросом по явным и неявным ожиданиям :blush:

Чуть не забыл
если используешь эту ботву

new AjaxElementLocatorFactory(webDriver, 10)

старайся не использовать Xpath .

Серьезно? А почему?

1 лайк

Присоединяюсь к вопросу?
Только надеюсь будете оперировать фактами, а не выдержками из javadoc который написан много лет назад неизвестно кем :slight_smile: