Page Objects (Locators) (sui:page) schema=html

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

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

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">
<h2 _ngcontent-jfq-c196="">Please select all names below, you might consider using for your next pet:</h2>
<mat-checkbox _ngcontent-jfq-c196="" class="mat-checkbox mat-accent" id="mat-checkbox-2">
</mat-checkbox>
<mat-checkbox _ngcontent-jfq-c196="" class="mat-checkbox mat-accent" id="mat-checkbox-3">
</mat-checkbox>
<mat-checkbox _ngcontent-jfq-c196="" class="mat-checkbox mat-accent" id="mat-checkbox-4">
</mat-checkbox>
</div>

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

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

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:

Methods:

Example:

Description:

equals





contains

<div id="" attribute:class="SearchButton" method="contains"/>



containsWord

Given 2 scenarios created:
This is the first example
This should be the second example

When:

  1. you create the locator in CAST from this xPath which is btw not working on the UI, only with CAST with text: //span[containsWord(text(),‘is’)]
    to this:
    <span id="exampleTextSpan" text="is" method="containsWord"/>


  2. you get the text with sui:get-text like this:

    <sui:get-text pageId="exampleTextSpan" name="exampleTextSpanOutput"/>

  3. and you create an echo about it like this:

    <echo message="+++++ exampleTextSpanOutput: ${exampleTextSpanOutput}"/>

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:

  1. if you have these 2 scenarios

  2. and if you change the text in the locator from text="is" to text="xxxxxxx"

  3. then the test will fail because it doesn't contain anything like the "xxxxxxx" and the auto-generated XPath by CAST will be this:
    //span[contains(concat(' ‘,normalize-space(text()), ’ ‘), ’ xxxxxxx ’)]

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:

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>







Related content