Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Python Selenium WebDriver. Writing my own expected condition

Tags:

I'm trying to write my own expected condition. What I need... I have an iframe. and I also have an image in it. I want to continue processing when image's scr will change. What I did:

class url_changed_condition(object):
    '''
    Checks whether url in iframe has changed or not
    '''
    def __init__(self, urls):
        self._current_url, self._new_url = urls

    def __call__(self, ignored):
        return self._current_url != self._new_url  

and later in the code I have:

def process_image(self, locator, current_url):
    try:
        WebDriverWait(self.driver, 10).until(ec.presence_of_element_located((By.TAG_NAME, u"iframe")))
        iframe = self.driver.find_element(*locator)
        if iframe:
            print "Iframe found!"
        self.driver.switch_to_frame(iframe)
        WebDriverWait(self.driver, 10).until(ec.presence_of_element_located((By.XPATH, u"//div")))

        # WebDriverWait(self.driver, 10).until(
            # url_changed_condition(
                # (current_url, self.driver.find_element(By.XPATH, u"//a/img").get_attribute(u"src"))))

        img_url = self.driver.find_element(By.XPATH, u"//a/img").get_attribute(u"src")
        print img_url
        self.search_dict[self._search_item].append(img_url)
        self.driver.switch_to_default_content()
    except NoSuchElementException as NSE:
        print "iframe not found! {0}".format(NSE.msg)
    except:
        print "something went wrong"
        import traceback
        import sys
        type_, value_, trace_ = sys.exc_info()
        print type_, value_
        print traceback.format_tb(trace_)
    finally:
        return current_url  

This code works, but returns the same url multiple times. The problem is when I uncomment url_changed_condition it falls with TimeoutException in
(current_url, self.driver.find_element(By.XPATH, u"//a/img").get_attribute(u"src"))
The line below it works fine... I don't get it.

like image 217
oleg.foreigner Avatar asked Oct 15 '13 09:10

oleg.foreigner


People also ask

What is custom wait in Selenium?

The wait applies the condition which tries finding the web element, depending on its status. If the condition can find the element, it returns the element as result. If it cannot find the element, the wait tries the condition again after a short delay.

What is explicit wait in Selenium?

Explicit Wait in SeleniumIf one sets an implicit wait command, then the browser will wait for the same time frame before loading every web element. This causes an unnecessary delay in executing the test script. Explicit wait is more intelligent, but can only be applied for specified elements.

What is implicit wait in Selenium Python?

An implicit wait tells WebDriver to poll the DOM for a certain amount of time when trying to find any element (or elements) not immediately available. This syntax should be used for python: self.driver.implicitly_wait(10) # seconds.


2 Answers

Looks like this topic misses an example of a Custom Expected Condition.

It is actually pretty easy. First of all, what is an Expected Condition in Python selenium bindings:

  • it is a new-style class (based on object)
  • it has __call__() magic method defined which returns a boolean

There is a big set of built-in expected condition classes.

Let's work through example. Let's say we want to wait until an element's text will start with a desired text:

from selenium.webdriver.support import expected_conditions as EC

class wait_for_text_to_start_with(object):
    def __init__(self, locator, text_):
        self.locator = locator
        self.text = text_

    def __call__(self, driver):
        try:
            element_text = EC._find_element(driver, self.locator).text
            return element_text.startswith(self.text)
        except StaleElementReferenceException:
            return False

Usage:

WebDriverWait(driver, 10).until(wait_for_text_to_start_with((By.ID, 'myid'), "Hello, World!"))
like image 149
alecxe Avatar answered Sep 30 '22 19:09

alecxe


Using the technique described by @alecxe , but modified slightly to cope with the expected_conditions which accept an element instead of a locator: (In this case, since there is no selenium.webdriver.support.expected_conditions.invisibility_of(element), I'm waiting for the is_displayed() method to signal False)

class wait_for_element_to_be_invisible(object):
    def __init__(self, element):
        self.element = element

    def __call__(self, driver):
        return not(self.element.is_displayed())

def test_collapsible_blocks_expand_or_collapse(self):
    self.browser.get(self.server_url+'/courses/1/')
    shadables = self.browser.find_elements_by_class_name('shade')
    for shadable in shadables:
        ## parent, then sibling element (*)
        shady_bit = shadable.find_element_by_xpath('../following-sibling::*')
        element = WebDriverWait(self.browser, 10).until(
            EC.visibility_of(shady_bit))
        shadable.click()
        element = WebDriverWait(self.browser, 10).until(
            self.wait_for_element_to_be_invisible(shady_bit))

The HTML fragment with the relevant bits of the DOM is:

<h4 class="shadable"><span class="shade" title="Show/Hide">↓</span>
  <a href="/link/to/uri">Title of Section</a>
</h4>
<article class="abstract">
  <p>Descriptive part which is shadable
  </p>
</article>`
like image 24
Chris McGinlay Avatar answered Sep 30 '22 18:09

Chris McGinlay