Отличие find_element от presence_of_element_located

Всем привет! Недавно столкнулся с такой проблеммой:
в сценарии теста жду пока появится элемент

WebDriverWait(self.parent, 40).until(EC.presence_of_element_located((By.CSS_SELECTOR, ".item")))

Этот шаг тест благополучно проходит, но потом:

first_item.element = self.parent.find_element_by_class_name('.item')

Выдает исключение ‘No such element’. Кто знает почему такое возможно? Может это из-за того, что я использую сначала поиск по css_selector, а потом по class_name? Хотя элемент с таким классом единственный на странице.

Может в поиске по классу точку в названии класса убрать?

self.parent.find_element_by_class_name('item')

Извините, поправочка
first_item.element = self.parent.find_element_by_css_selector('.item')
та же проблема

Ну тогда отличие именно в том, что в первом случае выполнение условия ОЖИДАЕТСЯ, а во втором нет.

То есть это не различие методов поиска в find_element и presence_of_element_located, а использование в первом случае механизма WebDriverWait()

Стоп, отбой… перечитал ещё раз первый пост. Видимо всё сложнее. Тогда нужны дополнительные сведения:

  1. код
  2. exception stacktrace

Что за первый параметр передаётся в WebDriverWait? Не уверен насчет Python, но в Java там передается экземпляр WebDriver

В python то же самое.
exception stacktrace:

Traceback (most recent call last):


 File "tests/annotation.py", line 88, in test_1_annotation
    item = search_results.get_first_item()
  File "/var/lib/jenkins/jobs/Annotation/workspace/tests/pskov_page_objects/widgets/search_results.py", line 37, in get_first_item
    first_item.element = self.parent.find_element_by_css_selector('.item')
  File "/usr/local/lib/python2.7/dist-packages/selenium/webdriver/remote/webdriver.py", line 361, in find_element_by_css_selector
    return self.find_element(by=By.CSS_SELECTOR, value=css_selector)
  File "/usr/local/lib/python2.7/dist-packages/selenium/webdriver/remote/webdriver.py", line 675, in find_element
    {'using': by, 'value': value})['value']
  File "/usr/local/lib/python2.7/dist-packages/selenium/webdriver/remote/webdriver.py", line 160, in execute
    self.error_handler.check_response(response)
  File "/usr/local/lib/python2.7/dist-packages/selenium/webdriver/remote/errorhandler.py", line 149, in check_response
    raise exception_class(message, screen, stacktrace)
NoSuchElementException: Message: u"no such element\n  (Session info: chrome=31.0.1650.57)\n  (Driver info: chromedriver=2.6.232917,platform=Linux 3.2.0-23-generic x86_64) (WARNING: The server did not provide any stacktrace information)\nCommand duration or timeout: 222 milliseconds\nFor documentation on this error, please visit: http://seleniumhq.org/exceptions/no_such_element.html\nBuild info: version: '2.37.0', revision: 'a7c61cb', time: '2013-10-18 17:14:00'\nSystem info: host: 'pskov-web', ip: '10.0.2.122', os.name: 'Linux', os.arch: 'amd64', os.version: '3.2.0-23-generic', java.version: '1.6.0_27'\nSession ID: e2e86cdee7bbe7bcdbd413dec523b45a\nDriver info: org.openqa.selenium.chrome.ChromeDriver\nCapabilities [{platform=LINUX, acceptSslCerts=true, javascriptEnabled=true, browserName=chrome, chrome={userDataDir=/tmp/.org.chromium.Chromium.jhhCov}, rotatable=false, locationContextEnabled=true, version=31.0.1650.57, takesHeapSnapshot=true, cssSelectorsEnabled=true, databaseEnabled=false, handlesAlerts=true, browserConnectionEnabled=false, webStorageEnabled=true, nativeEvents=true, applicationCacheEnabled=false, takesScreenshot=true}]" ; Screenshot: available via screen ; Stacktrace: Method newInstance threw an error in None 

Вот исполняемый код:

from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

from ItemControls import *


class SearchResultsItem(object):

    def __init__(self, driver):
        self.parent = driver
        # self.annotation = annotation.AnnotationControl(driver)

    def init_controls(self, controls):
        self.controls = {}
        for control in controls:
            control_instance = control(self.element)
            control_name = control_instance.__class__.__name__
            self.controls[control_name] = control_instance


class SearchResults(object):

    def __init__(self, driver):
        self.parent = driver
        WebDriverWait(self.parent, 40).until(EC.presence_of_element_located((By.ID, "items")), message='SearchResults widget not appeared')
        self.element = self.parent.find_element_by_id('items')
        WebDriverWait(self.parent, 40).until(EC.presence_of_element_located((By.CSS_SELECTOR, "#items .item")), message='SearchResults widget is empty')

    def get_first_item(self):
        first_item = SearchResultsItem(self.parent)
        WebDriverWait(self.parent, 40).until(EC.presence_of_element_located((By.CSS_SELECTOR, ".item")), message='SearchResults widget is empty')
        first_item.element = self.parent.find_element_by_css_selector('.item')
        return first_item

вопрос не совсем в тему, а аналога presence_of_element_located в C# я так понимаю, нет ?

ExpectedCondtitions в каждом языке немножко отличаются.
Вот коробочные C#, и ElementExists аналог питоновского presence_of_element_located.

@klysak07, какой рабочий локатор у вас, код вопроса не стыкуется с ошибкой?

можно упростить

self.element = WebDriverWait(self.parent, 40).until(EC.presence_of_element_located((By.ID, "items")), message='SearchResults widget not appeared')

при этом если будет StaleElement, на том же месте, то вероятно: элемент был, дождались, и он пропал из DOM.

Если елемент динамический я бы предложил (да поругают меня эксперты питона), засунуть в свойство класса

class SearchResults(object):
    element = property(lambda self: WebDriverWait(self.parent, 40).until(EC.presence_of_element_located((By.ID, "items")), message='SearchResults widget not appeared'))

    # или по длинному (3 строчки)... но читаемо
    @property
    def element(self):
      '''Fresh instance of items'''
      return WebDriverWait(self.parent, 40).until(EC.presence_of_element_located((By.ID, "items")), message='SearchResults widget not appeared')

это позволит на момент обращения к элементу получать именно его свежую копию, а не кешировать на момент конструирования объекта.

P.S. @polusok, не разобрался как делать цитату с кодом.

1 лайк