## Sahi - Web Automation and Test Tool

Documentation in this directory is not current. Please visit http://sahi.co.in/ for the latest documentation.

## APIs

The best way to learn how these APIs work is by recording actions using the Sahi controller and looking at the recorded code.
Accessor Functions : Form elements
Accessor Functions : Link
Accessor Functions : Tables
Accessor Functions : Generic
Action Scheduler Functions
Assertion Scheduler Functions
Text Access Functions
Text Verification boolean Functions
File Inclusion
Utility Functions
Database Functions
File Read Functions
Handling popup windows
(Top)

#### Accessor Functions : Form elements

_textbox(idStr)
_password(idStr)
_checkbox(idStr)
_textarea(idStr)
_select(idStr)
_option(selectElement, text)
_radio(idStr)
_image(idStr)
_button(idStr)
_submit(idStr)
_lastConfirm()
_lastPrompt()
_file(idStr)
(Top)

#### Accessor Functions : Link

_link(idStr)
(Top)

#### Accessor Functions : Tables

_table(idStr)
_cell(tableEl, rowNo, colNo)
_cell(tableEl, someTextWhichIdentifiesRow, someTextWhichIdentifiesColumn)
_cell(cellIdStr)
_row(tableEl, rowNo)
_row(tableEl, someTextWhichIdentifiesRow)
(Top)

#### Accessor Functions : Generic

_accessor(idStr)
(Top)

#### Scheduler Functions

Scheduler Functions behave differently from normal functions.
They schedule the execution of the action for later execution in a different thread. They essentailly have the effect of converting the whole statement into a string and adding it to a global array.
Each statement from the array is then executed one at a time, with a delay, when its turn comes.
Note: All these functions can also be made to execute instantly (and not delayed) by using __ (double underscores) instead of _ (single underscore)
(Top)

#### Action Scheduler Functions

These are Scheduler Functions
_click(jsElement)
_clickImage(jsElement)
_dragDrop(draggableElement, dropDestinationElement);
_setValue(jsElement, val)
_setSelected(jsElement, val)
_check(jsElement, val)
_simulateEvent(jsElement, ev)
_wait(millis)
_alert(str)
_setGlobal(name, value)
_call(fn())
_log(message, type) where type can be "success", "failure", "error", "info"
_highlight(jsElement)
_navigateTo("URLString")
_callServer("class_method", "querystring")
_addMock("pattern")
_addMock("pattern", "class_method")
_removeMock("pattern")
_expectConfirm()
_expectPrompt()
_setFile(_file("id"), filePath)
(Top)

#### Assertion Scheduler Functions

These are Scheduler Functions
_assertNotNull(jsElement, msg)
_assertNull(jsElement, msg)
_assertEqual(expected, actual, msg)
_assertNotEqual(expected, actual, msg)
_assertTrue(condition, msg)
_assertNotTrue(condition, msg)
(Top)

#### Text Access Functions

_getSelectedText(selectElement)
_getCellText(tableCellElement)
(Top)

#### Text Verification boolean Functions

_containsText(element, textToSearch)
_containsHTML(element, htmlToSearch)
(Top)

#### File Inclusion

_include(filePath)
_include(filePath)
One sah file may include other sah files, thus allowing logical separation of code.
Syntax: _include(file2.sah)
Example:
File create_customer.sah

        _include("create_customer_Functions.sah");
        createCustomer("Narayan", 1001, 27);

File create_customer_Functions.sah

        function createCustomer($name, $id, $age){
        _setValue(_textbox("name"), $name);
        _setValue(_textbox("id"), $id);
        _setValue(_textbox("age"), $age);
        }

(Top)

#### Utility Functions

_savedRandom(id, minNo, maxNo)
_resetSavedRandom(id)
_setGlobal(name, value)
_getGlobal(name)
_debug(msg)
_debugToErr(msg)
_debugToFile(msg, filePath)
_savedRandom(id, min, max)
If a script was recorded for say, creating a user, and if the user name is mandated to be unique in the application,
we need to add random numbers to the user name so that it remains unique.
One can obtain a random number by using _savedRandom(id, min, max).
During the first call to it, it creates a random number between min and max, associates with the id and returns the number.
On subsequent accesses with that id, it returns the same random number which it had created in the first access.
Example:

        var $x = _savedRandom("login", 100, 200); //sets $x to say 145 (a random number between 100, 200).
        //Defaults for min and max, if omitted, are 0 and 10000
        $y = _savedRandom("login", 100, 200); //will set $y to 145 again.
        $y = _savedRandom("login"); //will also set $y to 145.

The min and max are needed only during the first call.
_resetSavedRandom(id)
_resetSavedRandom(id) resets value of _savedRandom(id) to null;

_setGlobal(name, value) and _getGloblal(name)
Since a script may span across multiple web pages, variables from one page may need to be stored for later use.
For example, an id which is generated on customer creation may need to stored for later look up of the customer, on a different page.
This can be accomplished by _setGlobal(name, value) and _getGloblal(name).
Example:

        _setGlobal("customerId", _getCellText(_cell("custId"))); // sets the text in table cell with id "custId" into a
        global variable keyed by "customerId"

Then on a later page, one can retrieve the customerId through

        _setValue(_textbox("lookup"), _getGlobal("customerId")); // the second parameter retrieves the text stored.

These variables are stored on the server in a hashmap associated with the session.
Note: that all values will be stored as strings only.
Note: _setGlobal is a Scheduler Function.

_debug(msg)
Writes the message to the standard output stream. The messages will be visible on the window where the proxy is running unless redirected.
_debugToErr(msg)
Writes the message to the standard error stream. The messages will be visible on the window where the proxy is running unless redirected.
_debugToFile(msg, filePath)
Writes the message to the file specified.
(Top)

#### Handling popup windows

_popup(windowName)
_popup(windowName)
In order to execute sahi commands in a popup window, for example click a link,
use

        _popup("popupWinName")._click(_link("Click Me"));

where popupWinName was defined like this:

        window.open("http://popup.url", "popupWinName");

or

        <a href="http://popup.url" target="popupWinName">

Note that there may be problems in recording this.
(Top)

#### _callServer("class_method", "querystring")

_callServer allows Sahi to execute any server side code. Example:

        Create this Counter class. You will need sahi.jar in the compilation path.

        package sahi.ext;

        import net.sf.sahi.request.HttpRequest;
        import net.sf.sahi.response.HttpResponse;
        import net.sf.sahi.response.SimpleHttpResponse;

        public class Counter {
        static int counter = 0;

        public void incrementCounter(HttpRequest request) {
        counter++;
        }

        public HttpResponse getCounter(HttpRequest request) {
        return new SimpleHttpResponse(""+counter);
        }

        }

        Add this class to Sahi's class path.
        For example, if you are using sahi.bat, you could add it to the path like this:
        java -classpath ..\lib\sahi.jar;C:\sahiext\classes; net.sf.sahi.Proxy

        Restart Sahi

        Now we can call the methods of Counter class from any Sahi script in this way:
        var $currentCount = parseInt(_callServer("sahi.ext.Counter_getCounter"));
        _callServer("sahi.ext.Counter_incrementCounter");
        _assertEqual($currentCount + 1, _callServer("sahi.ext.Counter_getCounter"));

#### Mocks

Mocks are used to mock out responses to urls which match a particular pattern.
For example:
A web page has embedded advertisements in an iframe
and we do not wish to test these advertisements everytime we test our web page.
So we can add a mock by specifying

    _addMock("www[.]adserver[.]com", "sahi.ext.MyCustomMock_filterAds");

to our script.
Whenever Sahi encounters a URL request which matches www[.]adserver[.]com
It will delegate the response handling to sahi.ext.MyCustomMock's filterAds method.
One can call any class's any method, as long as the method has one of these two signatures.

        public net.sf.sahi.response.HttpResponse methodName(net.sf.sahi.request.HttpRequest request);

        public void methodName(net.sf.sahi.request.HttpRequest request);

If _addMock("pattern") is called without a second parameter,
net.sf.sahi.command.MockResponder.simple(HttpRequest) is used to process the request.
The response uses the template at htdocs/spr/simpleMock.htm.
One can modify this to show a generic mock response.
This script may explain mocks better:

        _navigateTo("http://localhost:10000/demo/index.htm");
        _assertNotNull(_link("Link Test"));
        _addMock(".*localhost.*");
        _navigateTo("http://localhost:10000/demo/index.htm");
        _assertNull(_link("Link Test"));
        _containsText(document.body, "http://localhost:10000/demo/index.htm");
        _removeMock(".*localhost.*");
        _navigateTo("http://localhost:10000/demo/index.htm");
        _assertNotNull(_link("Link Test"));

(Top)

#### Confirm

Javascript calls to confirm(msg) are mocked out by Sahi so that it does not stop the playback.
Sahi by default acts as if "OK" was clicked when a confirm dialog comes up.
It is possible to make the confirm return as if it was cancelled by setting

        _expectConfirm(label, false);

before the statement which triggers the confirm dialog.
If there was no expectation set, Sahi will return true.
It is also possible to get the text of the last occurred confirm dialog using

        _lastConfirm();

#### Example:

        <script type="text/javascript">
            function showConfirm(){
                var t1 = document.f1.t1;
                if (confirm("Some question?")){
                    t1.value = "oked";
                }else{
                    t1.value = "canceled";
                }
            }
        </script>
        <form name="f1">
            <input type="button" name="b1" value="Click For Confirm" onclick="showConfirm()">
            <input type="text" name="t1">
        </form>

        _click(_button("Click For Confirm"));
        _assertNotNull(_textbox("t1"));
        _assertEqual("oked", _textbox("t1").value);
        _assertEqual(_lastConfirm(), "Some question?");

        _expectConfirm("Some question?", false);
        _click(_button("Click For Confirm"));
        _assertNotNull(_textbox("t1"));
        _assertEqual("canceled", _textbox("t1").value);
        _assertEqual(_lastConfirm(), "Some question?"); //Kind of redundant here.

(Top)

#### Prompt

Javascript calls to prompt(msg) are mocked out by Sahi so that it does not stop the playback.
Sahi by default returns "" if a prompt dialog comes up.
It is possible to make the prompt return the value one wants, by specifying

        _expectPrompt(label, value);

before the statement which triggers the prompt dialog.
If there was no expectation set, Sahi will return "".
It is also possible to get the text of the last occurred prompt dialog using

        _lastPrompt();

#### Example:

        <script type="text/javascript">
        function showPrompt(){
            var t2 = document.f2.t2;
            t2.value = prompt("Some prompt?");
        }
        </script>
        <form name="f2">
            <input type="button" name="b1" value="Click For Prompt" onclick="showPrompt()"><br><br>
            <input type="text" name="t2">
        </form>

        _expectPrompt("Some prompt?", "abc")
        _click(_button("Click For Prompt"));
        _assertNotNull(_textbox("t2"));
        _assertEqual("abc", _textbox("t2").value);
        _assertEqual(_lastPrompt(), "Some prompt?");

(Top)

#### _setFile(_file("id"), filePath)

Form elements of type "file" cannot be populated using javascript on the browser.
So Sahi has a workaround for handling file uploads.
Sahi intercepts the request in the proxy, reads the file off the file system and inserts it into the multipart request.

        _setFile(_file("id"), "C:\\abc\\efg.jpg");

The file has to be present on that path on the machine running the proxy.
(Top)

#### _getDB("driver", "jdbcurl", "username", "password")

_getDB returns a sahiDB object.
sahiDB has two methods.
select(sql); // select statements
update(sql); // update/delete/insert statements
select returns a sequential array of associative arrays.
Eg.
For table "User"

ID | NAME | AGE
1 | Kamlesh | 28
2 | Arun | 30
3 | Raja | 35

    var db = _getDB("oracle.jdbc.driver.OracleDriver", "jdbc:oracle:thin:@dbserver:1521:sid", "username", "password")
    var $rs = db.select("select * from User");

    _assertEqual("1", $rs[0]["ID"]);
    _assertEqual("Kamlesh", $rs[0]["NAME"]);
    _assertEqual("28", $rs[0]["AGE"]);

    _assertEqual("2", $rs[1]["ID"]);
    _assertEqual("Arun", $rs[1]["NAME"]);
    _assertEqual("30", $rs[1]["AGE"]);

    _assertEqual("3", $rs[2]["ID"]);
    _assertEqual("Raja", $rs[2]["NAME"]);
    _assertEqual("36", $rs[2]["AGE"]);

The driver has to be present in the classpath of Sahi.
For example, if you are using sahi.bat, you could add it to the path like this:
java -classpath ..\lib\sahi.jar;C:\sahiext\driver.jar; net.sf.sahi.Proxy
(Top)

#### _readFile(fullFilePath)

_readFile(fullFilePath) returns the contents of a text file as a string.

        _readFile("C:\\abc\\data.txt");

The file has to be present on that path on the machine running the proxy.
One could then use the JS String's split method to get an array of lines.
eg.

            var $content = _readFile("C:\\abc\\data.txt");
            var $lines = $content.split("\n");

(Top)

Please send your feedback to V Narayan Raman.