def link(locator): """ Returns an :class:`Expression` for finding links matching the given locator. The query defines a link as an ``a`` element with an ``href`` attribute and will match links that meet at least one of the following criteria: * the element ``id`` exactly matches the locator * the element ``title`` matches the locator * the element text matches the locator * the ``alt`` of a nested ``img`` element matches the locator Args: locator (str): A string that identifies the desired links. Returns: Expression: An :class:`Expression` object matching the desired links. """ expr = x.descendant("a")[x.attr("href")][ x.attr("id").equals(locator) | x.attr("title").is_(locator) | x.string.n.is_(locator) | x.descendant("img")[x.attr("alt").is_(locator)]] return expr
def _locate_field(field_expr, locator): expr = field_expr[ x.attr("id").equals(locator) | x.attr("name").equals(locator) | x.attr("placeholder").equals(locator) | x.attr("id").equals(x.anywhere("label")[x.string.n.is_(locator)].attr("for"))] expr += x.descendant("label")[x.string.n.is_(locator)].descendant(field_expr) return expr
def test_creates_a_second_order_union(self): expr1 = x.descendant("p") expr2 = x.descendant("div") expr3 = x.descendant("span") collection1 = expr1.union(expr2)[x.attr("id") == "union-item-5"] collection2 = collection1.union(expr3[x.attr("id") == "union-item-6"]) xpath = to_xpath(collection2) results = self.find_all(xpath) self.assertEqual(results[0].text, "Fig")
def test_second_order_union_aliased_as_plus_sign(self): expr1 = x.descendant("p") expr2 = x.descendant("div") expr3 = x.descendant("span") collection1 = (expr1 + expr2)[x.attr("id") == "union-item-5"] collection2 = collection1 + expr3[x.attr("id") == "union-item-6"] xpath = to_xpath(collection2) results = self.find_all(xpath) self.assertEqual(results[0].text, "Fig")
def test_second_order_union_aliased_as_plus_sign(self): expr1 = descendant("p") expr2 = descendant("div") expr3 = descendant("span") collection1 = (expr1 + expr2)[attr("id") == "union-item-5"] collection2 = collection1 + expr3[attr("id") == "union-item-6"] xpath = to_xpath(collection2) results = self.find_all(xpath) self.assertEqual(results[0].text, "Fig")
def test_creates_a_second_order_union(self): expr1 = descendant("p") expr2 = descendant("div") expr3 = descendant("span") collection1 = expr1.union(expr2)[attr("id") == "union-item-5"] collection2 = collection1.union(expr3[attr("id") == "union-item-6"]) xpath = to_xpath(collection2) results = self.find_all(xpath) self.assertEqual(results[0].text, "Fig")
def test_aliased_as_plus_sign(self): expr1 = x.descendant("p") expr2 = x.descendant("div") collection = expr1 + expr2 xpath1 = to_xpath(collection.where(x.attr("id").equals("union-item-3"))) xpath2 = to_xpath(collection.where(x.attr("id").equals("union-item-4"))) results = self.find_all(xpath1) self.assertEqual(results[0].text, "Cherry") results = self.find_all(xpath2) self.assertEqual(results[0].text, "Date")
def test_creates_a_union_expression(self): expr1 = x.descendant("p") expr2 = x.descendant("div") collection = expr1.union(expr2) xpath1 = to_xpath(collection.where(x.attr("id").equals("union-item-3"))) xpath2 = to_xpath(collection.where(x.attr("id").equals("union-item-4"))) results = self.find_all(xpath1) self.assertEqual(results[0].text, "Cherry") results = self.find_all(xpath2) self.assertEqual(results[0].text, "Date")
def _locate_field(field_expr, locator): attr_matchers = ( x.attr("id").equals(locator) | x.attr("name").equals(locator) | x.attr("placeholder").equals(locator) | x.attr("id").equals( x.anywhere("label")[x.string.n.is_(locator)].attr("for"))) if capybara.enable_aria_label: attr_matchers |= x.attr("aria-label").is_(locator) expr = field_expr[attr_matchers] expr += x.descendant("label")[x.string.n.is_(locator)].descendant( field_expr) return expr
def xpath(locator): expr = x.descendant("a")[x.attr("href")] attr_matchers = (x.attr("id").equals(locator) | x.attr("title").is_(locator) | x.string.n.is_(locator)) if capybara.enable_aria_label: attr_matchers |= x.attr("aria-label").is_(locator) expr = expr[attr_matchers | x.descendant("img")[x.attr("alt").is_(locator)]] return expr
def test_where_aliased_as_square_brackets(self): expr1 = x.descendant("p") expr2 = x.descendant("div") collection = expr1.union(expr2) xpath1 = to_xpath(collection[x.attr("id").equals("union-item-3")]) xpath2 = to_xpath(collection[x.attr("id").equals("union-item-4")]) results = self.find_all(xpath1) self.assertEqual(results[0].text, "Cherry") results = self.find_all(xpath2) self.assertEqual(results[0].text, "Date")
def test_calls_the_given_xpath_function_with_the_current_node_as_the_first_argument( self): xpath = to_xpath( x.descendant("span").where( x.attr("id") == "string-length").text.method("string-length")) results = self.find_all(xpath) self.assertEquals(results, 11)
def test_used_as_an_expression(self): parent = x.descendant("div")[x.attr("id").equals("union")] expr1 = x.descendant("p") expr2 = x.descendant("div") collection = expr1.union(expr2) xpath1 = to_xpath(parent.descendant(collection[x.attr("id").equals("union-item-3")])) xpath2 = to_xpath(parent.descendant(collection[x.attr("id").equals("union-item-4")])) results = self.find_all(xpath1) self.assertEqual(results[0].text, "Cherry") results = self.find_all(xpath2) self.assertEqual(results[0].text, "Date")
def fillable_field(locator): """ Returns an `Expression` for finding fillable fields matching the given locator. The query defines a fillable field as one of the following: * an `input` element whose `type` is neither "checkbox", "file", "hidden", "image", "radio", nor "submit" * a `textarea` element The query will match fillable fields that meet at least one of the following criteria: * the element `id` exactly matches the locator * the element `name` exactly matches the locator * the element `placeholder` exactly matches the locator * the element `id` exactly matches the `for` attribute of a corresponding `label` element whose text matches the locator * the element is nested within a `label` element whose text matches the locator Args: locator (str): A string that identifies the desired fillable fields. Returns: Expression: An `Expression` object matching the desired fillable fields. """ field_expr = descendant("input", "textarea")[~attr("type").one_of( "checkbox", "file", "hidden", "image", "radio", "submit")] return _locate_field(field_expr, locator)
def field(locator): """ Returns an :class:`Expression` for finding form fields matching the given locator. The query defines a form field as one of the following: * an ``input`` element whose ``type`` is neither "hidden", "image", nor "submit" * a ``select`` element * a ``textarea`` element The query will match form fields that meet at least one of the following criteria: * the element ``id`` exactly matches the locator * the element ``name`` exactly matches the locator * the element ``placeholder`` exactly matches the locator * the element ``id`` exactly matches the ``for`` attribute of a corresponding ``label`` element whose text matches the locator * the element is nested within a ``label`` element whose text matches the locator Args: locator (str): A string that identifies the desired form fields. Return: Expression: An :class:`Expression` object matching the desired form fields. """ field_expr = x.descendant( "input", "select", "textarea")[~x.attr("type").one_of("hidden", "image", "submit")] return _locate_field(field_expr, locator)
def _set_radio(self, value): other_radios = self.native.xpath(to_xpath( x.anywhere("input")[x.attr("name") == self["name"]])) for node in other_radios: node.attrib.pop("checked", None) self.native.set("checked", "checked")
def test_allows_comma_separated_selectors(self): xpath = to_xpath( x.descendant()[x.attr("id").equals("moar")].css("div, p")) results = self.find_all(xpath) self.assertEqual(results[0].text, "chimp") self.assertEqual(results[1].text, "elephant") self.assertEqual(results[2].text, "flamingo")
def field(locator): """ Returns an :class:`Expression` for finding form fields matching the given locator. The query defines a form field as one of the following: * an ``input`` element whose ``type`` is neither "hidden", "image", nor "submit" * a ``select`` element * a ``textarea`` element The query will match form fields that meet at least one of the following criteria: * the element ``id`` exactly matches the locator * the element ``name`` exactly matches the locator * the element ``placeholder`` exactly matches the locator * the element ``id`` exactly matches the ``for`` attribute of a corresponding ``label`` element whose text matches the locator * the element is nested within a ``label`` element whose text matches the locator Args: locator (str): A string that identifies the desired form fields. Return: Expression: An :class:`Expression` object matching the desired form fields. """ field_expr = x.descendant("input", "select", "textarea")[ ~x.attr("type").one_of("hidden", "image", "submit")] return _locate_field(field_expr, locator)
def test_finds_multiple_kinds_of_nodes_regardless_of_the_context(self): xpath = to_xpath(x.descendant("div")[x.attr("id") == "woo"].anywhere("p", "ul")) results = self.find_all(xpath) self.assertEqual(inner_text(results[0]), "Blah") self.assertEqual(inner_text(results[3]), "A list") self.assertEqual(inner_text(results[4]), "A list") self.assertEqual(inner_text(results[6]), "Bax")
def test_finds_a_single_inexact_match(self, session): xpath_expr = x.descendant()[x.attr("class").is_("almost_singular but")] result = session.find("xpath", xpath_expr, match="prefer_exact", exact=False) assert result.text == "almost singular but not quite"
def test_picks_the_first_one_when_there_are_multiple_inexact_matches( self, session): xpath_expr = x.descendant()[x.attr("class").is_("almost_singul")] result = session.find("xpath", xpath_expr, match="prefer_exact", exact=False) assert result.text == "almost singular but not quite"
def test_picks_the_first_one_when_there_are_multiple_exact_matches( self, session): xpath_expr = x.descendant()[x.attr("class").is_("multiple")] result = session.find("xpath", xpath_expr, match="prefer_exact", exact=True) assert result.text == "multiple one"
def test_finds_a_single_exact_match_when_there_also_are_inexact_matches( self, session): xpath_expr = x.descendant()[x.attr("class").is_("almost_singular")] result = session.find("xpath", xpath_expr, match="prefer_exact", exact=True) assert result.text == "almost singular"
def href(node, href): if isregex(href): return bool(href.search(node["href"])) else: # For href element attributes, Selenium returns the full URL that would # be visited rather than the raw value in the source. So we use XPath. query = x.axis("self")[x.attr("href") == str_(href)] return node.has_selector("xpath", query)
def test_defaults_to_capybara_exact(self, session): xpath_expr = x.descendant("input")[x.attr("id").is_("est_fiel")] capybara.exact = True with pytest.raises(ElementNotFound): session.find("xpath", xpath_expr) capybara.exact = False session.find("xpath", xpath_expr)
def test_matches_encoded_unicode_characters(self): locator = "이름".encode("UTF-8") if sys.version_info >= (3, 0) else "이름" xpath = to_xpath(x.descendant("div")[x.string.n.is_(locator)]) results = self.find_all(xpath) self.assertEqual(results[0].get("id"), "unicode") xpath = to_xpath(x.descendant("div")[x.attr("title") == locator]) results = self.find_all(xpath) self.assertEqual(results[0].get("id"), "unicode")
def test_matches_quotes(self): locator = "Who's quotes? \"Their\" quotes." xpath = to_xpath(x.descendant("div")[x.string.n.is_(locator)]) results = self.find_all(xpath) self.assertEqual(results[0].get("id"), "quotes") xpath = to_xpath(x.descendant("div")[x.attr("title") == locator]) results = self.find_all(xpath) self.assertEqual(results[0].get("id"), "quotes")
def test_finds_all_nodes_when_no_arguments_given_regardless_of_the_context(self): xpath = to_xpath(x.descendant("div")[x.attr("id") == "woo"].anywhere()) results = self.find_all(xpath) self.assertEqual(results[0].tag, "html") self.assertEqual(results[1].tag, "head") self.assertEqual(results[3].tag, "body") self.assertEqual(inner_text(results[5]), "Blah") self.assertEqual(inner_text(results[9]), "A list") self.assertEqual(inner_text(results[12]), "A list") self.assertEqual(inner_text(results[14]), "Bax")
def test_matches_quotes(self): locator = "Who's quotes? \"Their\" quotes." xpath = to_xpath(descendant("div")[string.n.is_(locator)]) results = self.find_all(xpath) self.assertEqual(results[0].get_attribute("id"), "quotes") xpath = to_xpath(descendant("div")[attr("title") == locator]) results = self.find_all(xpath) self.assertEqual(results[0].get_attribute("id"), "quotes")
def test_matches_encoded_unicode_characters(self): locator = "이름".encode("UTF-8") if sys.version_info >= (3, 0) else "이름" xpath = to_xpath(descendant("div")[string.n.is_(locator)]) results = self.find_all(xpath) self.assertEqual(results[0].get_attribute("id"), "unicode") xpath = to_xpath(descendant("div")[attr("title") == locator]) results = self.find_all(xpath) self.assertEqual(results[0].get_attribute("id"), "unicode")
def test_matches_decoded_unicode_characters(self): locator = "이름" if sys.version_info >= (3, 0) else u"이름" xpath = to_xpath(x.descendant("div")[x.string.n.is_(locator)]) results = self.find_all(xpath) self.assertEqual(results[0].get("id"), "unicode") xpath = to_xpath(x.descendant("div")[x.attr("title") == locator]) results = self.find_all(xpath) self.assertEqual(results[0].get("id"), "unicode")
def frame(locator): """ Returns an `Expression` for finding frames matching the given locator. The query defines a frame as one of the following: * a `frame` element * an `iframe` element The query will match frames that meet one of the following criteria: * the element `id` exactly matches the locator * the element `name` exactly matches the locator Args: locator (str): A string that identifies the desired frames. Returns: Expression: An `Expression` object matching the desired frames. """ frames = descendant("frame") + descendant("iframe") return frames[attr("id").equals(locator) | attr("name").equals(locator)]
def frame(locator): """ Returns an :class:`Expression` for finding frames matching the given locator. The query defines a frame as one of the following: * a ``frame`` element * an ``iframe`` element The query will match frames that meet one of the following criteria: * the element ``id`` exactly matches the locator * the element ``name`` exactly matches the locator Args: locator (str): A string that identifies the desired frames. Returns: Expression: An :class:`Expression` object matching the desired frames. """ frames = x.descendant("frame") + x.descendant("iframe") return frames[x.attr("id").equals(locator) | x.attr("name").equals(locator)]
def test_finds_nodes_which_are_immediate_siblings_of_the_current_node(self): foo_div = x.descendant("p")[x.attr("id").equals("fooDiv")] monkey = x.descendant("p")[x.attr("title").equals("monkey")] xpath = to_xpath(foo_div.next_sibling("p")) results = self.find_all(xpath) self.assertEqual(inner_text(results[0]), "Bax") xpath = to_xpath(foo_div.next_sibling("ul", "p")) results = self.find_all(xpath) self.assertEqual(inner_text(results[0]), "Bax") xpath = to_xpath(monkey.next_sibling("ul", "p")) results = self.find_all(xpath) self.assertEqual(inner_text(results[0]), "A list") xpath = to_xpath(foo_div.next_sibling("ul", "li")) results = self.find_all(xpath) self.assertSequenceEqual(results, []) xpath = to_xpath(foo_div.next_sibling()) results = self.find_all(xpath) self.assertEqual(inner_text(results[0]), "Bax")
def test_finds_nodes_which_are_exactly_preceding_the_current_node(self): woo_div = x.descendant("p")[x.attr("id").equals("wooDiv")] gorilla = x.descendant("p")[x.attr("title").equals("gorilla")] xpath = to_xpath(woo_div.previous_sibling("p")) results = self.find_all(xpath) self.assertEqual(inner_text(results[0]), "Bax") xpath = to_xpath(woo_div.previous_sibling("ul", "p")) results = self.find_all(xpath) self.assertEqual(inner_text(results[0]), "Bax") xpath = to_xpath(gorilla.previous_sibling("ul", "p")) results = self.find_all(xpath) self.assertEqual(inner_text(results[0]), "A list") xpath = to_xpath(woo_div.previous_sibling("ul", "li")) results = self.find_all(xpath) self.assertSequenceEqual(results, []) xpath = to_xpath(woo_div.previous_sibling()) results = self.find_all(xpath) self.assertEqual(inner_text(results[0]), "Bax")
def link(locator): """ Returns an :class:`Expression` for finding links matching the given locator. The query defines a link as an ``a`` element with an ``href`` attribute and will match links that meet at least one of the following criteria: * the element ``id`` exactly matches the locator * the element ``title`` matches the locator * the element text matches the locator * the ``alt`` of a nested ``img`` element matches the locator Args: locator (str): A string that identifies the desired links. Returns: Expression: An :class:`Expression` object matching the desired links. """ expr = x.descendant("a")[x.attr( "href")][x.attr("id").equals(locator) | x.attr("title").is_(locator) | x.string.n.is_(locator) | x.descendant("img")[x.attr("alt").is_(locator)]] return expr
def optgroup(locator): """ Returns an :class:`Expression` for finding option groups matching the given locator. The query will match option groups whose ``label`` matches the locator. Args: locator (str): A string that identifies the desired option groups. Returns: Expression: An :class:`Expression` object matching the desired option groups. """ expr = x.descendant("optgroup")[x.attr("label").is_(locator)] return expr
def button(locator): """ Returns an :class:`Expression` for finding buttons matching the given locator. The query defines a button as one of the following: * a ``button`` element * an ``input`` element with a ``type`` of "button" * an ``input`` element with a ``type`` of "image" * an ``input`` element with a ``type`` of "reset" * an ``input`` element with a ``type`` of "submit" The query will match buttons that meet at least one of the following criteria: * the element ``id`` exactly matches the locator * the element ``value`` matches the locator * the element ``title`` matches the locator * the element text matches the locator * the element ``alt`` of an "image" ``input`` element matches the locator Args: locator (str): A string that identifies the desired buttons. Returns: Expression: An :class:`Expression` object matching the desired buttons. """ expr = x.descendant("button")[ x.attr("id").equals(locator) | x.attr("value").is_(locator) | x.attr("title").is_(locator) | x.string.n.is_(locator)] expr += x.descendant("input")[x.attr("type").one_of("submit", "reset", "image", "button")][ x.attr("id").equals(locator) | x.attr("value").is_(locator) | x.attr("title").is_(locator) | x.string.n.is_(locator)] expr += x.descendant("input")[x.attr("type").equals("image")][x.attr("alt").is_(locator)] return expr
def xpath(locator): input_button_expr = x.descendant("input")[x.attr("type").one_of( "submit", "reset", "image", "button")] button_expr = x.descendant("button") image_button_expr = x.descendant("input")[x.attr("type").equals( "image")] attr_matchers = (x.attr("id").equals(locator) | x.attr("value").is_(locator) | x.attr("title").is_(locator)) image_attr_matchers = x.attr("alt").is_(locator) if capybara.enable_aria_label: attr_matchers |= x.attr("aria-label").is_(locator) image_attr_matchers |= x.attr("aria-label").is_(locator) input_button_expr = input_button_expr[attr_matchers] button_expr = button_expr[attr_matchers | x.string.n.is_(locator) | x.descendant("img")[x.attr("alt"). is_(locator)]] image_button_expr = image_button_expr[image_attr_matchers] return input_button_expr + button_expr + image_button_expr
def table(locator): """ Returns an :class:`Expression` for finding tables matching the given locator. The query will match tables that meet at least one of the following criteria: * the element ``id`` exactly matches the locator * the element has a descendant ``caption`` element whose text matches the locator Args: locator (str): A string that identifies the desired tables. Returns: Expression: An :class:`Expression` object matching the desired tables. """ expr = x.descendant("table")[ x.attr("id").equals(locator) | x.descendant("caption").is_(locator)] return expr
def checkbox(locator): """ Returns an :class:`Expression` for finding checkboxes matching the given locator. The query will match checkboxes that meet at least one of the following criteria: * the element ``id`` exactly matches the locator * the element ``name`` exactly matches the locator * the element ``id`` exactly matches the ``for`` attribute of a corresponding ``label`` element whose text matches the locator * the element is nested within a ``label`` element whose text matches the locator Args: locator (str): A string that identifies the desired checkboxes. Returns: Expression: An :class:`Expression` object matching the desired checkboxes. """ field_expr = x.descendant("input")[x.attr("type").equals("checkbox")] return _locate_field(field_expr, locator)
def definition_description(locator): """ Returns an :class:`Expression` for finding definition descriptions matching the given locator. The query will match definition descriptions that meet at least one of the following criteria: * the element ``id`` exactly matches the locator * the element immediately follows a sibling ``dt`` whose text matches the locator Args: locator (str): A string that identifies the desired definition descriptions. Returns: Expression: An :class:`Expression` object matching the desired definition descriptions. """ expr = x.descendant("dd")[ x.attr("id").equals(locator) | x.previous_sibling("dt")[x.string.n.equals(locator)]] return expr
def fieldset(locator): """ Returns an :class:`Expression` for finding fieldsets matching the given locator. The query will match fieldsets that meet at least one of the following criteria: * the element ``id`` exactly matches the locator * the element has a child ``legend`` element whose text matches the locator Args: locator (str): A string that identifies the desired fieldsets. Returns: Expression: An :class:`Expression` object matching the desired fieldsets. """ expr = x.descendant("fieldset")[ x.attr("id").equals(locator) | x.child("legend")[x.string.n.is_(locator)]] return expr
def test_finds_nodes_regardless_of_the_context(self): foo_div = x.anywhere("div")[x.attr("id").equals("foo")] xpath = to_xpath(x.descendant("p")[x.attr("id").equals(foo_div.attr("title"))]) results = self.find_all(xpath) self.assertEqual(inner_text(results[0]), "Blah")
def test_aliased_as_ampersand(self): xpath = to_xpath(x.descendant("*")[x.contains("Bax") & x.attr("title").equals("monkey")]) results = self.find_all(xpath) self.assertEqual(results[0].get("title"), "monkey")
def test_finds_all_nodes_in_both_expressions(self): xpath = to_xpath(x.descendant("*")[x.contains("Bax").and_(x.attr("title").equals("monkey"))]) results = self.find_all(xpath) self.assertEqual(results[0].get("title"), "monkey")
def test_matches_all_nodes_where_the_condition_matches(self): xpath = to_xpath(x.descendant("*")[x.attr("id").one_of("foo", "baz")]) results = self.find_all(xpath) self.assertEqual(results[0].get("title"), "fooDiv") self.assertEqual(results[1].get("title"), "bazDiv")
def test_finds_nodes_that_contain_the_given_expression(self): expr = x.anywhere("div")[x.attr("title") == "fooDiv"].attr("id") xpath = to_xpath(x.descendant("div")[x.attr("title").starts_with(expr)]) results = self.find_all(xpath) self.assertEqual(results[0].get("id"), "foo")
def test_finds_nodes_that_begin_with_the_given_string(self): xpath = to_xpath(x.descendant("*")[x.attr("id").starts_with("foo")]) results = self.find_all(xpath) self.assertEqual(len(results), 2) self.assertEqual(results[0].get("id"), "foo") self.assertEqual(results[1].get("id"), "fooDiv")
def test_finds_all_nodes_when_no_arguments_given(self): xpath = to_xpath(x.descendant()[x.attr("id").equals("foo")].descendant()) results = self.find_all(xpath) self.assertEqual(inner_text(results[0]), "Blah") self.assertEqual(inner_text(results[4]), "A list")
def test_respects_previous_expression(self): xpath = to_xpath(x.descendant()[x.attr("id").equals("moar")].css("p")) results = self.find_all(xpath) self.assertEqual(results[0].text, "chimp") self.assertEqual(results[1].text, "flamingo")
def test_allows_comma_separated_selectors(self): xpath = to_xpath(x.descendant()[x.attr("id").equals("moar")].css("div, p")) results = self.find_all(xpath) self.assertEqual(results[0].text, "chimp") self.assertEqual(results[1].text, "elephant") self.assertEqual(results[2].text, "flamingo")