Sahi Pro - Sahi Accessor API Basics

Overview


Browser Accessor APIs help access elements on the browser.
They need to be executed on the browser and not in the proxy.
They should be used as parameters to Browser Action APIs.

All accessor APIs take an identifier and an optional domRelation.

Identifying unique element


For example,
<a href="http://sahi.co.in" id="sahi_link">Link to Sahi website</a>
can be represented in the following ways:

_link(12)Using index in the page; assuming it is the 13th link on the page.
_link("sahi_link")Using id as string
_link(/.*_link/)Using id as regular expression
_link("Link to Sahi website")Using visible text as string
_link(/Link to .* website/)Using visible text as regular expression
_link("/Link to .* website/")Using visible text as regular expression
_link({id:"sahi_link"})Using an associative array with id
_link({sahiText:"/Link to .*/"})Using an associative array with visible text as regular expression
_link({className:"low",sahiText:"/Link.*/"})Using an associative array with multiple attributes like className and sahiText

Identifying element among similar elements


For example,

<table>
    <tr>
        <td>User One</td>
        <td id="del1"><a href="/deleteUser?id=1">delete</a></td>
    </tr>
    <tr>
        <td>User Two</td>
        <td id="del2"><a href="/deleteUser?id=2">delete</a></td>
    </tr>
</table>

There are two delete links in this table and there may be more.

_link("delete")points to the first delete link. This is the same as _link("delete[0]")
_link("delete[1]")points to the second delete link; Note that indexing starts at 0
_link("/del/[1]")points to the second delete link; Note that indexing starts at 0

Using indexes works fine as long as the page is static, but it is not recommended for dynamic applications,
as it makes scripts fail when changes are made to the web pages.

Use of DOM Relation APIs


When elements are not uniquely identifiable by themselves, we should try to identify them in relation to either some element near them or by the element in which they are contained.

_near is a DOM relation marker which specifies that the element should be searched near another element.

_in is a DOM relation marker which specifies that the element should be searched within another element.

For example, in the above case, the second delete link is near User Two.

_link(0, _near(_cell("User Two"))) points to the 0th link near cell with text "User Two".
Note that the index is 0 here since it is the nearest link.
_link("delete", _near(_cell("User Two"))) points to the nearest link with text "delete" near cell with text "User Two".
Note that we do not need to specify "delete[1]" since it is the delete.
link
nearest to User Two.
_link(/del/, _near(_cell("User Two"))) points to the nearest link with text which matches
regular expression /del/ near cell with text "User Two".
_link("delete[2]", _near(_cell("User Two"))) points to the 3rd nearest link with text "delete" near cell with text "User Two".
_link("/del/[2]", _near(_cell("User Two"))) points to the 3rd nearest link with text matching /del/ near cell with text "User Two".
Note how the regular expression is appended with the index in square brackets
and quoted to make it a string

A similar DOM relation is _in

_link(0, _in(_cell("del2")))points to the 0th link in cell with id "del2"
_link("delete", _in(_cell("del2")))points to the link with text "delete" within cell with id "del2"

Use of Positional Relation APIs


Position relations like under, rightOf, leftOf etc. relate one element to another via their position.

One important frequent requirement in web applications is the assertion of elements in a column of a grid. For example

<table>
    <tr>
        <td>Name</td>
        <td>Delete</td>
        <td>Status</td>
    </tr>
    <tr>
        <td>User One</td>
        <td id="del1"><a href="/deleteUser?id=1">delete</a></td>
        <td>Active</td>
    </tr>
    <tr>
        <td>User Two</td>
        <td id="del2"><a href="/deleteUser?id=2">delete</a></td>
        <td>Inactive</td>
    </tr>
</table>

Name Delete Status
User One delete Active
User Two delete Inactive

In the above table:

_cell(0, _near(_cell("User One")), _under(_cell("Status")))Finds first cell near User One and under Status
_cell(0, _rightOf(_cell("User One")), _under(_cell("Status")))Finds first cell to the right
of User One and under Status
_cell("Inactive", _under(_cell("Status")))Finds first Inactive cell under Status

_near vs _rightOf or_leftOf

Using _near where the element to be found may or may not exist can give you unexpected results.

For example, in the table below
Name Delete Status
User One delete Active
User Two ? Inactive
User Two delete Inactive

Let us say we are looking to check if a delete link exists against all users.

_assertExists(_link("delete", _near(_cell("User Two")))) may be expected to fail, but it passes.
_link("delete", _near(_cell("User Two"))) actually points to the above highlighted link.

This is because, _near is a DOM relation API and finds an element within 7 ancestors (parent nodes) of the given anchor.
In our case this link was found within 2 ancestors of the cell in the next row.

The correct way of asserting this would be _assertExists(_link("delete", _rightOf(_cell("User Two")))).
_rightOf forces location only along the same line

Forcing Sahi Pro to ignore case when identifying elements

_setAccessorIgnoreCase

_setAccessorIgnoreCase($isIgnore)

Arguments
$isIgnoreboolean true or false

Details

If _setAccessorIgnoreCase(true) is called, on further statements, case differences will be ignored in identifiers of Accessors.

Given a link with text "Home", _link("Home") will identify the element,
but not _link("HOME") or _link("home").

If _setAccessorIgnoreCase(true) is called,
Then the same element can be identified using _link("Home"), _link("HOME") or _link("home")

Eg.
_assertExists(_link("Home")); // SUCCESS
_assertExists(_link("HOME")); // FAILURE
_assertExists(_link("/home/")); // FAILURE

_setAccessorIgnoreCase(true);
_assertExists(_link("Home")); // SUCCESS
_assertExists(_link("HOME")); // SUCCESS
_assertExists(_link("/home/")); // SUCCESS

_setAccessorIgnoreCase(false);
_assertExists(_link("Home")); // SUCCESS
_assertExists(_link("HOME")); // FAILURE
_assertExists(_link("/home/")); // FAILURE
info The default value of _setAccessorIgnoreCase is false. It can be forced to be true by default by adding
sahi.accessor.ignore_case=true
to sahi/userdata/config/userdata.properties