Created
January 5, 2022 14:48
-
-
Save IsmagilovQA/c793bd37be9a4eb9056dc9fb6a08041d to your computer and use it in GitHub Desktop.
COURSE [XPath selectors]
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Basics | |
Searching is based on Tags and Attributes. | |
Instructions: | |
/ -> absolute xpath, start searching from the root node | |
// -> relative xpath, starts from the node of your choice | |
//* -> we can put * if we don’t want to specify tag name (means ANY tag) | |
[@attributeName] -> @ means attribute in [ ] | |
‘Value’ -> all values we should put inside ‘ ‘ | |
//ul[@id=‘menu’]/li[contains(@class, ‘active’)] | |
//*[@checked] | |
//*[@name=‘email’] | |
//*[contains(@title, ’Name’)] | |
//*[starts-with(@src, ‘http’)] | |
//*[ends-with(@src, ‘.pdf’)] -> only in XPath v.2 (not all browser supports it) | |
Combined conditions: | |
//label | |
//label[.='E-mail'] -> label with text `E-mail` | |
//*[contains(@class, ‘error’)] | |
//label[contains(@class, ‘error’)] | |
//label[contains(@class, ‘error’) and contains(@class, ‘fatal’)] | |
//label[contains(@class, ‘error’) and contains(@class, ‘fatal’) and @for=‘email’] | |
Moving within DOM | |
//div[@id=‘main’]//p -> // means SOMEWHERE inside | |
//div[@id=‘main’]/p -> / means EXACTLY inside | |
//div[@id=‘main’]/div[2] -> the same as CSS selector: div#main>div:nth-of-type(2) | |
In XPath there is no first-child, last-child and nth-child | |
Method: Searching by two steps: | |
form = driver.findElement(By.id(“login”); | |
input = form.findElement(By.xpath(“.//input[@nmae=‘password’]”)) -> do not forget to set .// which means searching inside form (not from the start of DOM) | |
Advantages of XPath: | |
- Moving in any directions from child to parent (up): | |
//input[@id=‘search’]/../input[@type=‘button’] | |
- Searching by text: | |
//a[contains(.,’Edit’)] | |
- Subqueries: | |
//form[.//input[@name=‘password’]] -> .// means search relative to the current element | |
For XPath queries in dev tool (Console tab) we can use $x(“”) | |
http://wiki.umisoft.ru/%D0%9E%D1%81%D0%B8_%D1%8F%D0%B7%D1%8B%D0%BA%D0%B0_Xpath | |
XPATH TRAINING -> XPATH-LOCATORS-IN-SELENIUM | |
Links -> https://the-internet.herokuapp.com/ | |
GitHub -> https://github.com/dimashyshkin/xpath-locators-in-selenium | |
Relationship of Nodes: | |
Each element and attribute has one parent | |
* Parents | |
* Children -> elements inside another element | |
* Siblings -> nodes which have the same parent (потомство одних родителей) | |
* Ancestors -> are node parent, parents parent and so on (прародители) | |
* Descendants -> node children, children children (потомки, наследники) | |
<html> | |
<head> | |
<script> | |
<meta> | |
<title> | |
<html> is a parent of <head> element | |
<head> is a child of <html> element | |
<script>, <meta>, <title> they are all siblings, because they have same <head> parent | |
<html>, <head> are ancestors of <script> element | |
<script>, <head> are descendants of <html> element | |
Simple XPath | |
(Use this link: https://the-internet.herokuapp.com/challenging_dom) | |
//tag[@attribute=‘value’] -> formula | |
//div[] - inside we set predicate, div - it’s a tag | |
//div[@id] - here how we set attribute ‘id’ | |
//div[@id=‘content’] - here how we specify the value of the attribute ‘id’ (it can be @class, @name etc.) | |
//*[@id=‘content’] - look for any element that has id=‘content’ | |
//div[@*=‘content’] - look for div element with any attribute that has value =‘ content’ | |
//*[@*=‘content’] - look for any element with any attribute that has value =‘ content’ | |
/ and // inside Xpath | |
(Use this link: https://the-internet.herokuapp.com/challenging_dom) | |
//div[@id=‘content’]//a -> get all descendants links under div[@id=‘content’] element (any child any grandchild inside parent element) | |
//div[@id=‘content’]/a -> get all descendants links immediately only inside its parent element | |
//div[@class='large-2 columns']/a") - will look only children links inside div[@class='large-2 columns'] | |
//div[@class=‘large-12 columns large-centered’]/a -> it’s a grandparent and in this way we find nothing, because between div[@class=‘large-12 columns large-centered’] and a we have another div. So to solve this we should add it like this: | |
div[@class=‘large-12 columns large-centered’]/div/a | |
Position and Index | |
(Use this link: https://the-internet.herokuapp.com/challenging_dom) | |
(xpath)[index] | |
(xpath)[position()=index] | |
(xpath)[last()] | |
(xpath)[last() operator index] | |
//a[@href='#edit'] - find all links where attribute is @href=and value is ‘#edit' | |
(//a[@href='#edit’])[1] - find first link using index=1 | |
(//a[@href='#edit’])[position()=1] - the same result | |
(//a[@href='#edit’])[last()] - return last link in our collection | |
(//a[@href='#edit’])[last()-1] - return second link from the end | |
(//a[@href='#edit’])[last()-2] - return third link from the end | |
(//a[@href='#edit’])[position()<4] - return first 3 links | |
(//div[contains(@class, 'result__snippet')])[2] | |
XPath using Text | |
(Use this link: https://the-internet.herokuapp.com/disappearing_elements) | |
//tag[text()=‘text’] - this is the syntax | |
//tag[contains(text(), ‘text’)] | |
//tag[contains(., ‘text’)] | |
//tag[not(contains(., ‘text’))] | |
//a[.=‘link text’] - the same as find by link text | |
//a[contains(., ‘partial link text’)] - the same as find by partial link text. | |
//a[text()='Home'] - find element inside ‘a’ tag where text is ‘Home’ | |
//div[contains(@class, 'result__snippet')][contains(., 'bamboo')] -> will find by partial text in whole text in many desendents. | |
//div[contains(@class, 'result__snippet')][contains(text(), 'bamboo')] -> text() means direct textual content, the full text. | |
//div[contains(@class, 'result__snippet')][not(contains(., 'bamboo'))] | |
* | |
Searching By text (another examples): | |
//*[text() = 'hello'] | |
//*[normalize-space(text()) = 'hello'] | |
//*[normalize-space() = 'hello'] | |
//example[contains(text(), 'Hello')] | |
//example[. = 'Hello, I am an example .'] | |
https://stackoverflow.com/questions/3655549/xpath-containstext-some-string-doesnt-work-when-used-with-node-with-more - about text() and ‘.’ | |
* | |
Partial values (handling dynamic ids or big attributes) | |
(Use this link: https://the-internet.herokuapp.com/challenging_dom) | |
//tag[contains(@attribute, ‘value’)] | |
//tag[starts-with(@attribute, ‘value’)] | |
//tag[ends-with(@attribute, ‘value’)] | |
//tag[contains(text(), ‘text’)] | |
//tag[starts-with(text(), ‘text’)] | |
Here is the DOM: | |
<a id="1d41dee0-2989-0138-00d4-2631519864dd" href="" class="button">baz</a> | |
<a id="1d423ac0-2989-0138-00d5-2631519864dd" href="" class="button alert">qux</a> | |
<a id="1d43a380-2989-0138-00d6-2631519864dd" href="" class="button success">bar</a> | |
//a[contains(@id, '2631519864dd')] - will find all elements which meet the statement contains(@id, '2631519864dd’) - this only the part of id and it is not changed. | |
//a[starts-with(@class, 'button')] - will find all elements where @class attribute starts with same value ‘button’ | |
//*[contains(text(), 'The hardest part in')] - will find the text by using partial text | |
XPath operators (combining xpaths into one, |, or, and, and not(), not()) | |
(Use this link: https://the-internet.herokuapp.com/challenging_dom) | |
//a[@class='button'] | //a[@class='button alert’] - | |
we are looking for element //a[@class='button'] OR element //a[@class='button alert’] | |
//a[@class='button' or @class='button alert’] - same | |
//a[contains(@class, ‘button’) and not(contains(@class, ‘success’))] - we will find first two links and exclude with operator and not() the third link. | |
//th[not(text()=‘Lorem’)]- we will find all headers except header ‘Lorem’ | |
//a[not(contains(@class, 'header'))] | |
XPath Axes | |
* Ancestor -> selects all ancestors (parents, grandparents) of the current node | |
* Descendant -> selects all descendants (children, grandchildren) of the current node | |
* Parent -> select the parent of the current node | |
* Child -> selects all children of the current node | |
* Following-sibling -> selects all siblings after current node | |
* Preceding-sibling -> selects all siblings before current node | |
(Use this link: https://the-internet.herokuapp.com/tables) | |
///*[@id='table1']//td[text()='[email protected]']/following-sibling::td/a[@href='#delete'] -> remove specific user from the table (find [email protected] and go to delete button for this specific user); | |
//*[@id='table1']//td[text()='[email protected]']/parent::tr/child::td/a[@href='#delete'] -> get the same result but with another approach. | |
//a[.//img] - > will select links ‘a’ where inside it there is a ‘img’ tag. Dot here means to start searching from the current node not from beginning of doc. | |
//a[contains(@class, 'zcm__link')][preceding::a[@data-zci-link='web']] | |
//a[contains(@class, 'zcm__link’)][following::a[@data-zci-link='maps_expanded']] | |
//employee/ancestor::* -> select all ancestor nodes of the employee node | |
//ancestor::name -> select all ancestors of the name node in context node | |
child::* -> select all child nodes of the context node | |
child::employee -> select all child elements of employee node | |
//name/parent::* -> select parent node of the ‘name’ context node | |
//email/parent::employee -> return result node if employee node is parent node of context node | |
//employee[@id=3]/preceding::employee -> select all nodes (with child nodes) before the context node | |
//employee[@id=1]/following::employee[3] -> select all nodes (with child nodes) after the context node ([3] for specifying one particular element) | |
//name/self::* -> selects all names in the the current node | |
//descendant::employee -> select all descendants (children, grandchildren) of the employee node in context node | |
XPath in Selenium tests | |
// Get row for specific email: | |
WebElement row = driver.findElement(By.xpath("//*[@id='table1']//td[text()='" + email + "']/parent::*")); | |
// Another way to click Delete button for the row: | |
row.findElement(By.xpath("./child::td/a[@href='#delete']")); -> if we want to look only inside the row we should use ./ | |
// Also correct: | |
row.findElement(By.xpath("./descendant::a[@href='#delete']")); | |
AND operatior | |
//img[@width<20][@height<20] or the same will be -> | |
//img[@width<20 and @height<20] | |
OR operatior | |
//input[@name='q' or @id='search_form_input'] | |
https://developer.mozilla.org/en-US/docs/Web/XPath/Functions | |
//// | |
//*[@class='dx-template-wrapper']/*[.='4__company_appointment__12477__dxRadioGroup']//ancestor::td/following-sibling::td//dx-button | |
-> to find Delete button for particular row with particular id | |
//span[contains(text(),'Add Component’)]. -> add component dropdown | |
//span[contains(text(),'Data Field:')]//following-sibling::dx-text-box. -> select the input field in side column based on its label | |
///// | |
https://docs.google.com/document/d/1PdfKMDfoqFIlF4tN1jKrOf1iZ1rqESy2xVMIj3uuV3g/pub | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment