Page Objects (Locators) (sui:page) schema=html
a page object is a representation of a page element. It can be a button or a list item or any other custom built tag. We need an id to refer to them in our tests in pageId="" attributes
Usage
<sui:page id=""! schema="html"!>
<button id=""! attribute:xx=""? text=""? method=""? remoteId=""? />
<element id=""! type=""? xPath=""? attribute:xx=""? method=""? />
<ul id=""? attribute:xx=""? method=""?>
<li id=""! attribute:xx=""? text=""? method=""? index=""? sibling=""? directChild=""? />
</ul>
</sui:page>
! - mandatory, ? - optional
Where attributes can be defined after word attribute separated with colon e.g:
attribute:id
attribute:class
attribute:href
attribute:src
attribute:type
attribute:style
attribute:alt
attribute:title
attribute:aria-live
attribute:aria-label
Text
text is NOT an attribute. Therefore use the text="" in the condition to identify locators
attribute:id vs remoteId
for CSS selector:
attribute:id -> a[id =]
remoteId -> a#id
Supported methods:
Read More: Supported Methods Examples
equals (default value, doesn't have to be defined)
contains
containsWord
notEquals
notContains
matches (!!!! available just from XPath 2.0)
Supported schema:
Read More: Supported Schema Examples
html
winapp
wpf
Locators in Testifi:CAST
How to identify locators for Testifi:CAST
Locators
Use the minimum attributes to locate an element. The simplest is always the id (if available)
Definition - Relationships in Testifi:CAST
select the attribute(s) that identifies the element you want to locate
you can check the HTML source code in Chrome by pressing the f12 (or More tools/Developer tools) function button
make sure it identifies only one element
you can verify your xPath, by pressing ctrl+f and pasting your xPath there. You should see only one result
use as less attribute as possible
where attribute:id is the id from the HTML code and id is the id that we can use in Testifi:CAST framework (e.g in steps', scenarios' actions in the pageId attribute)
use multiple and/or custom tags in need
PageObject in Testifi:CAST for h1
<element type="app-login">
<h1 id="titleLogin" />
</element>
Across the different levels
Locating non-traditional HTML elements
In CAST, it's easy to locate/define traditional HTML elements, using their tags. So for example, if the user wants to locate a button, li, div, etc, there should be defined in the XML using the correct tag, like:
<button attribute:id="validId"/>, <li attribute:class="validClass"/> or <div attribute:type="validType"/>
However, it could happen that there is a non-traditional element in the HTML, for example: app-page-view-test-scenario, mat-form-field, app-library-drag-drop-element, app-pet-list, etc.
In this case, use the <element/> tag, and its 'type' parameter.
So if you would like to locate: app-page-view-test-scenario element, which having a class="ng-star-inserted" you should do it like this: <element type="app-page-view-test-scenario" attribute:class="ng-star-inserted"/>
As you see, the name of the element is going to the 'type' parameter, and the tag is always 'element'.
Using index attribute
Many times, our locators can't be unique and for a given locator we get a list instead. To get the unique element from the list we can provide an index value.
In CAST the XPath index starts with 1 just like it works in the browser's developer tools from release 2.2.20-GA; before that, the index starts from 0
Index | HTML | Testifi:CAST | XPath | Comments |
---|---|---|---|---|
No | <button id="petButton" attribute:id="timeout-btn"/> | //button[@id='timeout-btn'] | Without index, the locator is returning a list of 4 elements | |
Yes | <button id="petButton" attribute:id="timeout-btn" index="1"/> | (.//button[@id='timeout-btn'])[1] | With index, the locator is returning the required value |
Example Page Objects
page objects should be listed between <sui:page> and </sui:page> tags to identify elements on a webpage
HTML | Testifi:CAST | XPath | Comments |
---|---|---|---|
<input _ngcontent-bxt-c188="" matinput="" type="text" class="mat-input-element mat-form-field-autofill-control ng-tns-c58-23 cdk-text-field-autofill-monitored cdk-text-field-autofilled" id="mat-input-5" aria-invalid="false" aria-required="false"/> | <input id="inputField" attribute:id="mat-input-5"/> | //input[@id="mat-input-5"] | ids such as "mat-input-5" are often not reliable. Sometimes they change after navigating through the page. It is better to not use them as an identifier. Using an XPath can be more reliable in such cases |
<button _ngcontent-bxt-c188="" mat-flat-button="" color="primary" id="login__submit" class="mat-focus-indicator ng-tns-c188-22 mat-flat-button mat-button-base mat-primary"> ... </button> | <button id="theButton" attribute:class="mat-flat-button mat-button-base mat-primary" method="contains"/> | //button[contains(@class,"mat-flat-button mat-button-base mat-primary")] | |
<div class="mat-form-field-infix ng-tns-c58-4"> ... </div> | <div id="currentPetDropDown" attribute:class="mat-form-field-wrapper ng-tns-c58-4"/> | //div[@class="mat-form-field-infix ng-tns-c58-4"] | |
<div _ngcontent-jfq-c196="" class="form__checkboxes form__container"> | When the following element is already defined: <element type="mat-checkbox" id="charlieCheckbox" attribute:id="mat-checkbox-2"/> <element type="mat-checkbox" id="siblingOfCharlie" sibling="charlieCheckbox" index="1"/> | //mat-checkbox[@id = 'mat-checkbox-2']/following-sibling::mat-checkbox[1] | |
<li> <a id="navigation.ticketOverview" href="" /> </li> | <element id="overviewTab" xPath="//li[a[@id="navigation.ticketOverview"]]" /> | //li[a[@id="navigation.ticketOverview"]] |
Example HTML
<li class="option-charcoal" id="option17">
<a href="javascript:void(0)" name="charcoal" id=swatch17" class="swatch-link swatch-link-92 has-image" title="Charcoal" style="height: 21px; width: 21px; line-height: 21px;">
<span class="swatch-label" style="height: 21px; width: 21px; line-height: 21px;">
<img src="http://demomagento.testifi.io/magento/media/catalog/swatches/1/21x21/product/s/w/swatch_msj006c-charcoal.png" alt="Charcoal" width="21" height="21">
</span>
</a>
</li>
Good Practices
relevant HTML part | Testifi:CAST | Generated XPath by CAST | Comment /Explanation |
---|---|---|---|
<img
src="http://demomagento.testifi.io/magento/media/catalog/swatches/1/21x21/product/s/w/swatch_msj006c-charcoal.png"
alt="Charcoal" width="21" height="21"> | <img id="imgColourCharcoal" attribute:alt="Charcoal" /> | //img[@alt="Charcoal"] | To identify the image with alt attribute id is used in the scenario / step |
<a href="javascript:void(0)" name="charcoal" id=swatch17"
class="swatch-link swatch-link-92 has-image" title="Charcoal"
style="height: 21px; width: 21px; line-height: 21px;">
...
</a> | <a id="aColourCharcoal" attribute:id="swatch17" /> | //a[@id='swatch17" | To identify the link (a) with an id attribute 'id' (not the attribute:id) is used in the scenario / step |
<a href="javascript:void(0)" name="charcoal" id=swatch17"
class="swatch-link swatch-link-92 has-image"
title="Charcoal" style="height: 21px; width: 21px; line-height: 21px;">
...
</a> | <a id="aColourCharcoal" attribute:class="swatch-link-92 has-image" method="contains" /> | //a[contains(@class," swatch-link-92 has-image ")] | The class can be a good choice to identify a page element. Make sure it is unique and if you use just part of the classes, also include the method="contains" |
<a href="javascript:void(0)" name="charcoal" id=swatch17"
class="swatch-link swatch-link-92 has-image" title="Charcoal"
style="height: 21px; width: 21px; line-height: 21px;">
<span class="swatch-label" style="height: 21px; width: 21px; line-height: 21px;">
<img
src="http://demomagento.testifi.io/magento/media/catalog/swatches/1/21x21/product/s/w/swatch_msj006c-charcoal.png"
alt="Charcoal" width="21" height="21">
</span>
</a> | <a attribute:id="swatch17">
<span>
<img id="imgColourCharcoal" />
</span>
</a> | When there is no unique identifier we can build a path to locate the element. We can add an attribute check for each level, but the 'id' must be on the element we want to use in the tests |
Bad Practices
relevant HTML part | Testifi:CAST | Comment /Explanation |
---|---|---|
<img
src="http://demomagento.testifi.io/magento/media/catalog/swatches/1/21x21/product/s/w/swatch_msj006c-charcoal.png"
alt="Charcoal" width="21" height="21"> | <img id="imgColourCharcoal"
attribute:src="http://demomagento.testifi.io/magento/media/catalog/swatches/1/21x21/product/s/w/swatch_msj006c-charcoal.png" /> | To identify the image with alt src is not recommended. Just imagine if we have more environment, the link will change |
<a href="javascript:void(0)" name="charcoal" id=swatch17"
class="swatch-link swatch-link-92 has-image" title="Charcoal"
style="height: 21px; width: 21px; line-height: 21px;">
...
</a> | <a id="aColourCharcoal" attribute:href="javascript:void(0)" /> | href is generally not a good idea to use for same reason as src for img. Neither java script functions, it can be more than one on the page and also can be changed. |
<a href="javascript:void(0)" name="charcoal" id=swatch17"
class="swatch-link swatch-link-92 has-image" title="Charcoal"
style="height: 21px; width: 21px; line-height: 21px;">
...
</a> | <a id="aColourCharcoal" attribute:title="Charcoal" /> | can be a good choice if it is unique and the page is not (and won't be) translated to other languages where this attribute can be different |
<div id="petDropDownList" attribute:id="mat-select-1-panel" /> | <sui:get-text pageId="petDropDownList" name="resultText" generator="css" includeSubElements="true" /> | with generator="css" we can force to use the css selector like By.cssSelector: div[id = 'mat-select-1-panel'] |
Examples for supported methods:
equals (default value, doesn't have to be defined)
contains
containsWord
notEquals
notContains
matches (!!!! available just from XPath 2.0)
Methods: | Example: | Description: |
---|---|---|
equals | ||
contains | <div id="" attribute:class="SearchButton" method="contains"/> | |
containsWord | Given 2 scenarios created: When:
Then the echo will give back to you only 1 result and the echo will be this: +++++ exampleTextSpanOutput: This is the first example | containsWord finds only the one word which contains exactly the word in this case "is", not that "is" word which is inside the "This". As an FYI info:
|
notEquals | ||
notContains | ||
matches |
Difference between contains and containsWord with an example:
This is the first example
This should be the second example
contains “is” would find 3 "is":
"is" inside the first "This"
"is"
"is" inside the second "This"
containsWord “is” would find only 1 "is" which is a separate word
Examples for supported schema:
Methods: | Example: | Description: |
---|---|---|
html | <sui:page id="petstore:loginPage" schema="html">
<button id="loginButton" attribute:id="login" />
<element id="loginIcon"! type="uniqueType" attribute:id="angularIcon" />
</sui:page> | |
winapp | <sui:page id="petstore:loginPage" schema="winapp">
<Button id="loginButton" attribute:id="Login" />
<element id="loginIcon"! type="UniqueType" attribute:id="WindowsIcon" />
</sui:page> | |
wpf | <sui:page id="petstore:loginPage" schema="wpf">
<Button id="loginButton" attribute:id="Login" />
<element id="loginIcon"! type="UniqueType" attribute:id="WpfIcon" />
</sui:page> |