Skip to content

Instantly share code, notes, and snippets.

@IsmagilovQA
Created January 5, 2022 14:48
Show Gist options
  • Save IsmagilovQA/c793bd37be9a4eb9056dc9fb6a08041d to your computer and use it in GitHub Desktop.
Save IsmagilovQA/c793bd37be9a4eb9056dc9fb6a08041d to your computer and use it in GitHub Desktop.
COURSE [XPath selectors]
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