Sahi
Sahi
0
Web Automation and Testing Tool User Manual
Contents
Sahi - Introduction .............................................................................................................................................................................7
Sahi Architecture ....................................................................................................................................................... 8
Starting Sahi ...................................................................................................................................................................................... 15 Recording through Sahi ................................................................................................................................................................ 16 Playing back through Sahi .......................................................................................................................................................... 21
Running a test from the controller ........................................................................................................................... 21 View Logs ............................................................................................................................................................... 22
Distributing tests across different machines using ant: ..................................................................... 26 Load testing using ant: ........................................................................................................................ 27 Sahi Pro Controller.......................................................................................................................................................................... 29
Recorder Tab ........................................................................................................................................................... 29 The Anchor Button .................................................................................................................................................. 30
Example............................................................................................................................................... 30
Using the Sahi Script Editor .................................................................................................................................... 31
Sahi Pro
Exception Handling using try-catch........................................................................................................................................ 43 Recovering without try-catch using _setRecovery............................................................................................................ 44 Script Lifecycle Call Back Functions........................................................................................................................................ 45 Sahi Pro Excel Framework .......................................................................................................................................................... 46
Sample Excel Sheet ................................................................................................................................................. 46 Loading Sahi script libraries .................................................................................................................................... 46 Executing the Excel Sheet ....................................................................................................................................... 47 Play back reports/logs ............................................................................................................................................. 47
Syntax ...................................................................................................................................................................... 49
Identifiers ............................................................................................................................................ 58 DOM relations ..................................................................................................................................... 59 Positional Relations............................................................................................................................. 60 Accessors of HTML Elements: ............................................................................................................. 61 Accessors of Table related elements .................................................................................................. 65 Accessors of Form elements ............................................................................................................... 66 Accessors of HTML5 Form elements................................................................................................... 68 Accessors of parent DOM Nodes ........................................................................................................ 70 Accessors of IFrames and Rich Text Editors based on IFrames in editable mode .............................. 71 Generic accessors ............................................................................................................................... 71 Browser popups: Alerts, Confirms and Prompts................................................................................ 72 Utility functions to access properties of elements ............................................................................. 74 Marker functions to show DOM relation............................................................................................ 76 Sahi Pro Tyto Software Pvt. Ltd. 4
Mouse Actions .................................................................................................................................... 77 Focus Actions ...................................................................................................................................... 82 Key Actions.......................................................................................................................................... 83 Data Input Actions .............................................................................................................................. 84 Assertions............................................................................................................................................ 87 Utility actions ...................................................................................................................................... 91 Actions to mock out particular URLs .................................................................................................. 98 Actions to set expectations for javascript confirms and prompts .................................................... 100 Actions used for debugging .............................................................................................................. 101 Toggle KeepAlive Actions .................................................................................................................. 103 Cookie related actions ...................................................................................................................... 103 Download related actions ................................................................................................................. 104
Miscellaneous APIs ............................................................................................................................................... 106
Functions available on browser and on proxy .................................................................................. 106 Functions available on proxy only .................................................................................................... 109 Recovery functions ........................................................................................................................... 111 Working with databases ................................................................................................................... 112 Working with files ............................................................................................................................. 115 Data driven testing............................................................................................................................ 117 APIs for browser detection ............................................................................................................... 119 APIs for screen capture ..................................................................................................................... 119 Appendix 3: Integrate with Jenkins ..................................................................................................................................... 121 Appendix 3: Configuring Sahi with Xvfb............................................................................................................................ 124
What is xvfb? ........................................................................................................................................................ 124 Installing Xvfb: ..................................................................................................................................................... 124 Setting up Xvfb on display 1: ................................................................................................................................ 125 Running test in Xvfb headless browser through Sahi:........................................................................................... 125
Appendix 4: Reading XML with Sahi .................................................................................................................................... 126 Sahi Pro Tyto Software Pvt. Ltd. 5
Sahi Pro
Sahi - Introduction
Sahi is an automation tool to test web applications. Sahi injects javascript into web pages using a proxy and the javascript helps automate web applications. Sahi is a tester friendly tool. It abstracts out most difficulties that testers face while automating web applications. Some salient features include: Excellent recorder Platform and browser independence No XPaths No waits Multithreaded (parallel) playback Excellent Java interaction Inbuilt reporting
Sahi Pro builds on Sahi Open Source to add significant time saving features. Sahi Pro adds the ability to: Spread playback across multiple machines Edit scripts and create functions right from the Controller Build object repositories automatically while recording Automatically accept SSL certificates Automate your flex components with sfl - Sahi Flex (Beta) Compare logs and screenshots to compare the outcomes of scripts run on different browsers Customize your logs as XML, HTML or directly feed them to a database. Modify XSL style sheets to get custom reporting according to your needs. Use inbuilt Excel based Framework which lets non-technical users participate in automation
Sahi Pro
Sahi Architecture
Sahi uses a HTTP proxy at its core to inject javascript into web pages. The injected Javascript uses custom code to identify elements on the browser and simulate actions like click, type etc. on them.
Html responses which pass through the proxy are modified such that JavaScript is injected at the start and the end of the response. This allows the browser to record and playback scripts and talk back to the proxy when needed. Apart from handling requests for pages that the browser requests, Sahis proxy also handles custom commands related to recording, playback etc. which the browser sends. The architecture of Sahi allows Sahi to be used on any browser or operating system. Sahi relies on two core technologies/concepts: HTTP proxy to inject code Javascript code to find elements and emulate actions
Both these technologies are basic building blocks of internet technologies and will necessarily be supported by all browsers, making Sahi very easily extensible to newer browsers or newer versions of browsers.
Sahi Pro
Sahi Advantages
Sahi is an engineering solution for an engineering problem. We use heuristics based algorithms, fuzzy logic, thresholds etc. to arrive at a solution which is 99.9% correct. Sahi also exposes the ability to be exact when needed, making Sahi very suitable for any web application.
Sahi automatically goes through frames, iframes etc. to find elements. One does not need to explicitly select a frame in the automation script. So if developers moved the login fields into an iframe, Sahi will still work with your older scripts.
UI Relations
Sahi is slightly different from other automation technologies. It relies less on the underlying code and more on the business intention of the user interface. Code changes are frequent in an evolving application and relying on business intention is a more stable way of writing automation test cases. Sahi does this through what is called UI Relations. UI Relations help identify one element with respect to another element which communicates strong business intention. For example: The cost of "Laptop" in a tabular structure may be represented in Sahi as _cell(0, _near(_div("Laptop")), _under(_div("Cost"))) This represents the cell which is near "Laptop" and under "Cost". Note that even if there are more columns or rows added in that grid structure, this always points to the correct cell. If we had used the column index or row index, the test would break as soon as the location of Laptop or Cost changed.
Parallel Playback
Sahi allows Parallel or Multithreaded playback. Multiple tests can be run simultaneously to reduce playback time, thus reducing your build time and shortening your feedback cycle. One can also spread the tests across machines or on the cloud and get one consolidated report, all stored in a database.
Sahi Pro
Getting Started
Prerequisites
Java 1.5 or above is needed for running Sahi.
Installation of Sahi
Once Sahi Pro is downloaded, double click on the jar file to run the installer. If that does not work, navigate to the folder on command prompt and run java -jar install_sahi_pro_v36_yyyymmdd.jar On starting the installer, follow the steps below:
Sahi Pro
10
Sahi Pro
11
Sahi Pro
12
Sahi Pro
13
Sahi Pro
14
Starting Sahi
Start Sahi Dashboard by any of the following methods: 1) Double click on the desktop shortcut 2) Go to Start -> All Programs -> Sahi -> Start Sahi 3) Start from the command line. Windows: Go to <SahiPro>\userdata\bin and run start_dashboard.bat Linux Go to <SahiPro>/userdata/bin and run start_dashboard.sh The Sahi Dashboard starts the Sahi proxy, and allows launching of different browsers. Sahi automatically modifies the browsers proxy settings, so that requests go through the Sahi Proxy (localhost:9999)
Sahi Configuration
If the browsers are not visible on Dashboard, look here for trouble shooting: http://sahi.co.in/w/trouble-shooting-sahi Sahi Pro Tyto Software Pvt. Ltd. 15
Sahi Pro
16
Press ALT and double click on the window which you want to record. The Sahi Controller will pop up. (If that does not work, press CTRL and ALT keys together and then double click. Make sure popup blockers are turned off)
Sahi Pro
17
On the controller, go to the Record tab. Give a name for the script, and click Record. (.sah is optional)
Navigate on your website like you normally would. Most actions on the page will now get recorded. o The currently recorded step is visible in the Evaluate Expression box
Sahi Pro
18
Add an assertion: o Move the mouse over any html element while pressing Ctrl key. The Accessor field will get populated in the controller.
o o
Click the Assert button to generate assertions for the element. They will appear in the Evaluate Expression box. Click Test > to check that the assertions are true. You can evaluate any javascript using Evaluate Expression and Test >. Actions performed via the controller will not be automatically recorded. Only actions performed directly on the page are automatically recorded. This lets you experiment on the webpage at recording time without impacting the script. Once satisfied, click on Append to Script. This will add the assertions to the script.
Sahi Pro
Note that the controller can be closed and reopened at any time, without disrupting recording. The recorded script is stored in <sahi_pro>\userdata\scripts directory. The recorded script can be viewed and edited easily through any text editor. Sahi Scripts are simple text files which use Javascript syntax. The script can be edited even while recording, so that logical segregation into functions etc. can be done as recording happens.
Sahi Pro
20
Steps will start executing, and the controller will be updated accordingly. Once finished, SUCCESS or FAILURE will be displayed at the end of the steps.
Note that the controller can be closed at any time, without disrupting playback.
Sahi Pro
21
View Logs
On the controller, go to Playback tab and click on View Logs link at the bottom right. It will open a window with the results neatly formatted in HTML. Clicking on a line in the logs will drill down to exact line in script. Logs show all the assertion in green. If the assertion has failed it will show in red. You can click on any of these lines to go into the line of script to debug. You can also view the logs at http://localhost:9999//_s_/dyn/pro/DBReports
Sahi Pro
22
Suites can be run from a command prompt or through ant. They cannot be run from the Controller. Suite logs show details of all scripts run
Sahi Pro
23
Eg.
One can directly click on the Bin link on the Dashboard to open a command prompt at usedata/bin NOTE: Example scripts and suites can be found in SAHI_HOME/userdata/scripts/demo folder
Sahi Pro
24
This can be invoked as ant browsertests. Attribute suite browserType baseurl sahihost sahiport failureproperty haltonfailure singlesession threads Parameters (sahi) Description path to suite or test file The name of the browserType as specified in browser_types.xml url relative to which all urls to be tested will be resolved IP or hostname of server where Sahi is running port where Sahi is running Name of property which will be set to false in case build fails. Takes "true" or "false". Specifies if build should stop executing other tests if one test fails. Takes "true" or "false". If true, all scripts run sequentially in a single browser session without closing the browser. threads is ignored. Number of simultaneous browser instances where sahi tests will be run. Works for IE, Firefox and Chrome Required Yes Yes Yes Yes Yes Yes Yes No No
Nested Elements report Sahi Pro Specifies type and location of report types can be junit html tm6 Tyto Software Pvt. Ltd. No 25
Distributing tests across different machines using ant: Use this code snippet to distribute tests across different machines.
<taskdef name="sahid" classname="in.co.sahi.ant.DAntRunner" classpath="lib/ant-sahi.jar"/> <target name="failsahi" if="sahi.failed"> <fail message="Sahi tests failed!"/> </target> <target name="drun"> <tstamp> <format property="ts" pattern="yyyy_MM_dd_HH_mm_ss" locale="en, IN"/> </tstamp> <property name="tempdest" value="temp/scripts/${ts}"/> <sahid suite="${tempdest}/demo/demo.suite" baseurl="http://${urlbase}/demo/" sahihost="localhost" sahiport="9999" failureproperty="sahi.failed" haltonfailure="false" browserType="firefox"> <sync originFolder="userdata/scripts" destFolder="${tempdest}" ignorePattern=".*(svn|copied).*"/> <node host="localhost" port="9999"/> <node host="othermachine" port="9999"/> </sahid> <antcall target="failsahi"/> </target>
Parameters (sahid) Description path to suite or test file The name of the browserType as specified in browser_types.xml url relative to which all urls to be tested will be resolved IP or hostname of server where Sahi is running port where Sahi is running Name of property which will be set to false in case build fails. Takes "true" or "false". Specifies if build should stop executing other tests if one test fails.
Additionally, the user will have to specify the machines on which the tests have to be distributed. Specify them in the nested node tag. Parameters (node) Attribute host port Description Name or IP Address of the machine Port where Sahi is running on the remote machine Required Yes Yes
For the tests to be distributed across remote machines, the user will also need to make sure that the scripts are available in each of those machines. This is taken care of by the nested sync tag. Sahi Pro Tyto Software Pvt. Ltd. 26
Parameters (sync) Attribute originFolder destFolder ignorePattern Description Scripts folder to copy over Folder which will contain the scripts after copy Any files with a specific pattern that need to be ignored Required Yes Yes No
Load testing using ant: This code snippet can be used to perform load testing. (Read more about load testing with Sahi here)
<taskdef name="sahiload" classname="in.co.sahi.ant.DAntLoadRunner" classpath="lib/ant-sahi.jar"/> <target name="failsahi" if="sahi.failed"> <fail message="Sahi tests failed!"/> </target> <target name="dloadrun"> <tstamp> <format property="ts" pattern="yyyy_MM_dd_HH_mm_ss" locale="en, IN"/> </tstamp> <property name="tempdest" value="temp/scripts/${ts}"/> <sahiload subject="${tempdest}/demo/load/subject.sah" baseurl="http://${urlbase}/demo/training/" sahihost="localhost" sahiport="9999" failureproperty="sahi.failed" haltonfailure="false" browserType="firefox" noise="${tempdest}/demo/load/noise.sah" noiseBrowserType="phantomjs" min="1" max="5" incrementBy="2" interval="5"> <sync originFolder="userdata/scripts" destFolder="${tempdest}" ignorePattern=".*(svn|copied).*"/> <node host="localhost" port="9999"/> <node host="othermachine" port="9999"/> </sahiload> <antcall target="failsahi"/> </target>
Sahi Pro
27
Parameters (sahiload) Attribute subject Description Path to script whose steps need to be measured periodically at different loads. browserType The name of the browserType as specified in browser_types.xml baseurl url relative to which all urls to be tested will be resolved sahihost IP or hostname of server where Sahi is running sahiport port where Sahi is running failureproperty Name of property which will be set to false in case build fails. haltonfailure Takes "true" or "false". Specifies if build should stop executing other tests if one test fails. noise Script to generate the load noiseBrowserType Browser to run the noise on (Ideally, use a headless browser like phantomjs) min Minimum number of threads to run the noise interval Time (in seconds) to wait before incrementing the load incrementBy Number of threads to increase after an interval max Maximum number of threads to run the noise Required Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes Yes
It is also possible to involve multiple machines in creating the load by specifying the machine names in the node tag. Note: Sample examples are shipped with Sahi Pro and are available in sahis root folder in demo.xml
Sahi Pro
28
Sahi Pro
29
If we hover over the third textbox, it is identified as _textbox(q[2]) Instead, we first CTRL-Hover over Python Cookbook; the Accessor field shows:
Now if we CTRL-Hover over the textbox, we see that the Accessor now resolves the textbox in relation with Python Cookbook.
Sahi Pro
30
Select the steps you want to convert to a function and click Create Function. The Right hand panel will extract function parameters. Specify a function name, and choose the required parameters and constants. Click on Continue to create function code. If not satisfied, Click Undo to revert.
Sahi Pro
31
Sahi Pro
32
Playback Tab
Playback Tab
Next step to execute. Changing this value, will cause Sahi to skip steps till this.
A copy of the test script currently loaded for play back is displayed in the web browser.
Sahi Pro
33
sahid task which can distribute tests across multiple machines. <sync> copies the originFolder to destFolder. destFolder will be created in sahi_pro/userdata directory on every node. In this target we are dynamically creating a directory every time, based on the timestamp. <node> The nodes have to be specified using <node> tags. browserType specifies the type of browser to pick. This maps to the <name> attribute in browser_types.xml NOTE: Refer to userdata/bin/drun.bat and drun.sh for running from command line
Sahi Pro
34
Reports
All reports are logged into the database by default. They can also be logged into the filesystem based on settings in sahi.properties or userdata.properties reports.filesystem.html.enabled=true reports.filesystem.xml.enabled=true reports.db.enabled=true reports.sql.enabled=true # Database logging. # Tables are created using sahi/user data/config/db/create_report_tables.sql db.driver_name=org.h2.Driver db.jdbc_url=jdbc:h2:$userDir/database/db0;DB_CLOSE_DELAY=-1 db.user_name=sa db.password= db.script_gen_xsl=$userDir/config/db/script_sql_gen.xsl
Reports can be accessed at http://localhost:9999/_s_/dyn/pro/DBReports This URL is available as a link at the bottom of Playback tab.
Sahi Pro
35
Database Report
Sahi Pro
36
Suite Report
Script Report
Sahi Pro
37
HTML, SQL and XML logs are created in a time-stamped folder under sahi_pro/userdata/logs/playback/<suiteLogFileName>
HTML logging converts result XML to HTML using XSL files in sahi_pro/userdata/config/reports. Database logging is done by first converting XML to SQL using XSL files in sahi_pro/userdata/config/db and then firing those queries against the database configured in sahi.properties or userdata.properties. Database tables are created if required using sahi_pro/userdata/config/db/create_report_tables.sql Sahi Pro is bundled with H2, a filesystem based small database. The database files are in sahi_pro/userdata/database. The files db0.h2.db, db0.trace.db and db0.lock.db can be deleted to recreate logs from scratch. Sahi Pro Tyto Software Pvt. Ltd. 38
Statements:
Statements are normal lines of code. They end with a semi-colon. For example, _click(_link("Login"));
Variable declaration:
Syntax var $variableName = value; or var $variableName; // declaration $variableName = value; // assignment var $username = "SahiTestUser"; var $password; // declaration; $password = $username + "_password"; // "SahiTestUser_password" All variables start with a $. The keyword var is used for local variables.
Example
Note
Function declaration:
Syntax function functionName($parameter1, $parameter2) { // statements } //function declaration function login($usr, $pwd){ _click(_link("Login")); _setValue(_textbox("username"), $usr); _setValue(_password("password"), $pwd); _click(_submit("Login")); } //function call login("sahi_user", "secret");
Example
Comments:
// This is a single line comment /* This is a multiline comment. This has two lines */ Sahi Pro Tyto Software Pvt. Ltd. 39
if statements:
Syntax if (condition) { // statements } if ($username == "PartnerUser"){ _click(_link("Partner Login")); } If the if condition is page dependent, use if (_condition(booleanExpression)) For example, if (document.loginForm.userName =="karthik"){...} should be written as if (_condition(document.loginForm.userName == "karthik")){...} NOTE _condition need not be added if the condition does not depend on any pages DOM.
Example
for loops:
Syntax for (var $i=0; $i<$max; $i++){ // statements } // This loop will login with user1, password1, user2, password2 etc. // login and logout are custom functions. for (var $i=0; $i<10; $i++){ login("user"+$i, "password"+$i); logout(); } Do not use a condition which depends on a pages DOM. for (var $i=0; $i<document.links.length; $i++) {...} //WRONG If you want to iterate over page DOM variable, first take a snapshot of it using _set, and then use the variable. For example, <browser> var $anchors = []; function getLinkIds(){ var retVal = []; var links = document.links; for (var i=0; i<links.length; i++){ retVal[i] = links[i].innerHTML; } return retVal; } </browser> _set ($anchors, getLinkIds()); for (var $i=0; $i<$anchors.length; $i++) {...} //RIGHT Sahi Pro Tyto Software Pvt. Ltd. 40
Example
Note
while loops:
Syntax while (condition) { // statements } Example $i = 0; while ($i++ < 10) { login("user"+$i, "password"+$i); logout(); } If the while loop condition is page dependent, use while (_condition(booleanExpression)){...} For example, while (document.loginForm.userName != "karthik"){ // some statements } should be written as while (_condition(document.loginForm.userName != "karthik")){ // some statements } Note You do not need to add _condition if the condition is not dependent an the page DOM.
Sahi Pro
41
Advanced Scripting
While Sahi scripts can easily be recorded, as a project grows in size, the scripts may have to be more logically organized into functions and split into multiple files. The following section gives more details on the Sahi Script and the rules to follow. Sahi script is based on Javascript. The constructs of javascript, like functions, variables, loops, conditional statements etc. are all available in Sahi script. But the script is parsed and transformed slightly in the Sahi proxy server before execution. To keep matters simple, follow these rules.
Sahi Pro
42
Sahi Pro
43
Sahi Pro
44
For example, function onScriptEnd(){ _click(_button("Logout")); } function onScriptError(){ _alert(">> In onScriptError"); } function onScriptFailure(){ _alert(">> In onScriptFailure"); } _navigateTo("http://sahi.co.in/demo/training/"); _setValue(_textbox("user"), "test"); _setValue(_password("password"), "secret"); _click(_submit("Login"));
Sahi Pro
45
Checks Invalid login message "test" "bad password" "Invalid username or password"
These tests talk mostly in the language of the business (also called a Domain Specific Language or DSL for that business), and hide away all the implementation details of clicking buttons and populating textboxes.
The code in books_lib.sah is given below: Sahi Pro Tyto Software Pvt. Ltd. 46
function login($username, $password){ _setValue(_textbox("user"), $username); _setValue(_password("password"), $password); _click(_submit("Login")); } function addBooks($numJava, $numRuby, $numPython){ _setValue(_textbox("q", _near(_cell("Core Java"))), $numJava); _setValue(_textbox("q", _near(_cell("Ruby for Rails"))), $numRuby); _setValue(_textbox("q", _near(_cell("Python Cookbook"))), $numPython); _click(_button("Add")); } function verifyTotal($total){ _assertEqual($total, _textbox("total").value); } function logout(){ _click(_button("Logout")); } function verifyNotLoggedIn(){ _assertExists(_textbox("user")); } function verifyErrorMessage($msg){ _assert(_isVisible(_div("errorMessage"))); _assertEqual($msg, _getText(_div("errorMessage"))); }
Sahi Pro
47
Starting script Expand All | Collapse All loadSahi Check shopping cart total [Documentation] login addBooks verifyTotal logout Test login error message [Documentation] login verifyNotLoggedIn verifyErrorMessage "Invalid username or password" Stopping script Checks Invalid login message "test" "bad password" "sample_lib.sah" Smoke test for add books "test" 3 1640 "secret" 2 1
Please refer to sahi/userdata/scripts/demo/framework folder for some examples. IMPORTANT NOTES 1. You may need to close the Excel sheet before running it 2. Only the first sheet will be executed. The first sheet should be called Sheet1 and should not be renamed 3. MS Excel needs to be installed on the system 4. Due to a bug, numbers need to be formatted as text in Excel. One can do this by entering a single quote before entering the number For example type '23 instead of 23.
Sahi Pro
48
Syntax
Test Case Key word Argument 1 Argument Argument 2 3 Very first line of sheet Blank lines are ignored Loads a Sahi script with required function definitions Param2 New test case started. StepOne(Param1, Param2) is called. StepTwo(Param3) is called New test case started. String values are quoted
loadSahi
"custom_lib.sah"
Step One
Param1
Param3 25 "age"
Step Two
Test [Documentation] Some Case description Three about the test case Step One 25 // Step Two Step Two Param5 Param6
"age"
New test case started. String values are quoted Commented step using //
Spaces will be removed from keywords and corresponding functions invoked. The rules for writing the Excel sheet are as follows The first line should be populated with Test Case | Key word | Argument 1 | Argument 2 | Argument 3 The names of the columns are not important, but they should not be left blank If the first column is populated, a new test case is started. The second column holds keywords. Keywords are mapped to functions in the included Sahi script. They can be user defined functions or Sahi APIs themselves
Sahi Pro
49
For example, login "test" "secret" in the excel sheet, maps to the javascript call login("test", "secret"); _assertEqual _getText(_cell("msg")) "abcd" becomes _assertEqual(_getText(_cell("msg")), "abcd"); Variables The Excel framework also supports variables, eg. $userId=createUserInGroup "My name" "My group" verifyUserCreated $userId "My name" "My group" or $msg= _assertEqual _getText(_cell("msg")) $msg "abcd"
SetUp and TearDown Different test cases may need the same steps to be executed before and after. For example, one may need to login before and logout after each test case. This can be accomplished through global SetUp and TearDown blocks. TearDown will be called inspite of any errors or failures in the testcase. [Global] [SetUp] _log login
"secret"
[TearDown] _click _button("Logout") _log "In Global Teardown" Verify books total addBooks verifyTotal 3 1650 3 2000 2 1
Verify books again addBooks verifyTotal This will execute as: Sahi Pro
50
"In Global Setup" "test" "secret" 3 2 1 1650 _button("Logout") "In Global Teardown"
"In Global Setup" "test" "secret" 3 2 2 2000 _button("Logout") "In Global Teardown"
Sahi Pro
51
Create [CreateKeyword] Add AddBooksCheck Books Key Word Check [Arguments] $java
[CreateKeyword] command creates a keyword called "Add Books Check" These are the arguments or parameters that "Add Books Check" takes as input
[Documentation] Data drivable add books check addBooks $java $ruby $python verifyTotal $total
So now, a call to "Add Books Check" like this: Add Books Check 3 2 1 1650
Sahi Pro
52
login "test" "secret" Add Books Check 3 2 1 _click _button("Logout") login "test" "secret" Add Books Check 4 5 0 _click _button("Logout") login "test" "secret" Add Books Check 0 1 9 _click _button("Logout")
1650
2100
3350
Sahi Pro
53
Compile using Adobe Flash Builder (Add SWC files to Flex Builder projects)
In Flex Builder, select your Flex project in the Navigator. Select Project > Properties. The Properties dialog box appears. Select Flex Compiler in the tree to the left. The Flex Compiler properties panel appears. In the "Additional compiler arguments" field, enter the following command: -include-libraries "sfl4.swc"
In Flex Builder, the entries in the include-libraries compiler option are relative to the Flex Builder installation directory. The default location of this directory on Windows is C:\Program Files\Adobe\Flex Builder. After compilation refresh the browser cache, to make sure that the modified yourapp.swf is available.
Sahi Pro
54
From the dashboard, open any browser and navigate to your flex application. Press ALT and double click on the window which you want to record. Sahis Controller window will pop up. You can now start recording your Flex application. NOTE:
Ctrl + hover (to get a flex elements accessor) will work only if the Flex object is in focus. To do this, you will have to first click on the Flex object. Flex APIs are different from the normal JavaScript APIs. Eg. _f("yuiswf0").textinput("username2")
Sahi Pro
55
Instructions:
1. Get the headless browser: PhantomJS Read this article to add PhantomJS to Sahi. 2. Start Sahi Pro. PhantomJS should be visible on the Dashboard as one of the browsers. 3. On the dashboard, click on the "Bin" link. This will open up a command prompt at userdata/bin 4. On the command prompt, run dload.bat demo/load/noise.sah demo/load/subject.sah http://sahi.co.in/demo/training firefox This will do the following: 1. 2. 3. 4. 5. 6. Run 1 (min) threads of noise.sah on PhantomJS (This will not be visible) Run subject.sah on firefox browser and store the time of steps. Wait for 5 seconds (interval) Run 2 (incrementby) more threads of noise.sah on PhantomJS Run subject.sah on firefox and store results Keep incrementing the noise threads at periodic intervals, run the subject, and store results, till it reaches max noise threads.
Once done, click on "Logs" link on the Dashboard to view results. To test your application, go to userdata/scripts/demo/load folder. 1. Open noise.sah and add your sequence of steps. These steps should be representative of a normal user interaction. Note that your steps should be in a while(true){} loop so that the threads don't die out. (Refer to existing noise.sah) 2. Open subject.sah and specify the sequence of steps whose reaction times you would like to measure at different loads. The parameters min, max, incrementby, interval etc. can be edited in dload.bat file. It is also possible to involve multiple machines in creating the load by modifying the "NODES" variable (Look in dload.bat)
Sahi Pro
56
NOTE: Once changes are made, you will have to click on the Save button and restart Sahi for those changes to take effect.
Sahi Pro
57
Appendix 2: APIs
Browser Accessor APIs :
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. Identifiers can either be a numerical index or a property as specified in each case. Identifiers which are not numerical can either be a string or a javascript regular expression. Identifiers which are strings can also have an index along with them in square brackets as part of the string.
Identifiers Simple case where links are uniquely identifiable: For example: <a href="http://sahi.co.in" id="sahi_link">Link to Sahi website</a> This can be represented in the following ways _link(12) _link("sahi_link") _link(/.*_link/) _link("Link to Sahi website") _link(/Link to .* website/) _link("/Link to .* website/") Using index in a page; assuming this is the 13th link on the page Using id as a string Using id as a regular expression Using visible text as a string Using visible text as a regular expression Using visible text as a regular expression
Case where multiple elements with similar property are present: 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> Sahi Pro Tyto Software Pvt. Ltd. 58
There are two delete links in this table and there may be more. _link("delete") _link("delete[1]") _link("/del/[1]") points to the first delete link. This is the same as _link("delete[0]"). points to the second delete link; Note that indexing starts at 0. 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. DOM relations 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"))) _link("delete", _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. 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. points to the nearest link with text which matches regular expression /del/ near cell with text User Two. points to the 3rd nearest link with text delete near cell with text 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
points to the 0th link in cell with id del2 points to the link with text delete within cell with id del2
Sahi Pro
59
Positional Relations _under is a Positional Relation which helps narrow down elements under another element. Specifically it looks for elements which have the same left offset (within a threshold) as the anchoring element. One important frequent requirement in web applications is the assertion of elements in a column of a grid. For example Name Delete User One User Two delete delete
<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> In the above table: _cell(0, _near(_cell("User One")), _under(_cell("Status"))) _cell("Inactive", _under(_cell("Status"))) Finds first cell near User One and under Status Finds first Inactive cell under Status
Sahi Pro
60
Accessors of HTML Elements: API HTML Identifier Example API HTML Identifier Notes Example API HTML Identifier Example API HTML Identifier Example API HTML Identifier Example API HTML Identifier Example _link(identifier[, domRelation]) <a href="http://u/r/l" id="id">visible text</a> index, visible text, id _link("Sahi Website"); _image(identifier[, domRelation]) <img src="/path/to/images/add.gif" id="id" alt="alt" title="title"> index, title or alt, id, file name from src _image(add.gif) for an image with src /path/to/images/add.gif _image("title"); _label(identifier[, domRelation]) <label id="id">text</label> index, id, text _label("text"); _listItem(identifier[, domRelation]) <li id="id">text</li> index, id, text _listItem("text"); _div(identifier[, domRelation]) <div id="id">text</div> index, id, text _div("text"); _span(identifier[, domRelation]) <span id="id">text</span> Index,id,text _span("text");
Sahi Pro
61
API HTML Identifier Example API HTML Identifier Example API HTML Identifier Example API HTML Identifier Example API HTML Identifier Example API HTML Identifier Example
_spandiv(identifier[, domRelation]) <span id="id">text</span> or <div id="id">text</div> Index, id, text _spandiv("text"); _heading1(identifier[, domRelation]) <h1 id="id">text</h1> text, id _heading1("text"); _heading2(identifier[, domRelation]) <h2 id="id">text</h2> text, id _heading2("text"); _heading3(identifier[, domRelation]) <h3 id=id>text</h3> text, id _heading3("text"); _heading4(identifier[, domRelation]) <h4 id=id>text</h4> text, id _heading4("text"); _heading5(identifier[, domRelation]) <h5 id=id>text</h5> text, id _heading5("text");
Sahi Pro
62
API HTML Identifier Example API HTML Notes Example API HTML Identifier Example API HTML Identifier Example API HTML Identifier Example API HTML Identifier Example
_heading6(identifier[, domRelation]) <h6 id=id>text</h6> text, id _heading6("text"); _title() <title>text</title> Returns title of the page _title("text"); _area(identifier[, domRelation]) <area shape="rect" class="className" id="id" href="http://u/r/l" /> id, title|alt, href, shape, className, index _area("id"); _blockquote(identifier[, domRelation]) <blockquote class="className" id="id">sahiText</blockquote> sahiText, id, className, index _blockquote("sahiText"); _bold(identifier[, domRelation]) <b class="className" id="id">sahiText</b> sahiText, id, className, index _bold("sahiText"); _code(identifier[, domRelation]) <code class="className" id="id">sahiText </code> sahiText, id, className, index _code("sahiText");
Sahi Pro
63
API HTML Identifier Example API HTML Identifier Example API HTML Identifier Example API HTML Identifier Example API HTML Identifier Example API HTML Identifier Example
_emphasis(identifier[, domRelation]) <em class=className id=id>sahiText</em> sahiText, id, className, index _emphasis("sahiText"); _italic(identifier[, domRelation]) <i class="className" id="id">sahiText</i> sahiText, id, className, index _italic("sahiText"); _list(identifier[, domRelation]) <ul class="className" id="id">sahiText</ul> <ol class="className" id="id">sahiText</ol> id, className, index _list("sahiText"); _map(identifier[, domRelation]) <map class="className" id="id"></map> name, id, title, className, index _map("id"); _canvas(identifier[, domRelation]) <canvas class=classname id=id></canvas> sahiText, id, className, index _canvas("id"); _preformatted(identifier[, domRelation]) <pre class="className" id="id">sahiText</pre> sahiText, id, className, index _preformatted("sahiText");
Sahi Pro
64
_strong(identifier[, domRelation]) <strong class="className" id="id">sahiText</strong> sahiText, id, className, index _strong("sahiText"); _abbr(identifier[, domRelation]) <abbr class="className" id="id">sahiText</abbr> sahiText, id, className, index _abbr("sahiText"); 2011-07-19
Accessors of Table related elements API HTML Identifier Example API HTML _cell(identifier[, domRelation]) <td id="id">text</td> index, id, sahiText, className _cell("text"); _cell(tableElement, rowText, colText) <td id="id">text</td> <table id="tableId"> <tr><td> header1 </td><td> header2 </td><td> header3 </td></tr> <tr><td> value11 </td><td> value12 </td><td> value13 </td></tr> <tr><td> value21 </td><td> value22 </td><td> value23 </td></tr> </table> _cell(_table("tableId"), "header2", "value11"); This will point to cell with valuevalue11 _row(identifier[, domRelation]) <tr><td>te</td><td>xt</td></tr> id, className, sahiText, index _row(text) can be used to identify rows with text. Useful to look for cells in a row. _cell(text1,_in(_row(someClassName))) _row("text");
Example
Example
Sahi Pro
65
_table(identifier[, domRelation]) <table id="id">text</table> index, id, className _table("text"); _tableHeader(identifier[, domRelation]) <th id="id">text</th> sahiText, id, className _tableHeader("text");
Accessors of Form elements API HTML Identifier Example API HTML Identifier Example API HTML Identifier Example API HTML Identifier Example _button(identifier[, domRelation]) <input type="button" name="name" id="id" value="value"> <button type="button" name="name" id="id">value</button> value, name, id, index, className (sahiText: valid for <button/>) _button("value"); _checkbox(identifier[, domRelation]) <input type=checkbox name=name id=id value=value> name, id, value, className, index _checkbox("name"); _password(identifier[, domRelation]) <input type="password" name="name" id="id" value="value"> name, id, index, className _password("name"); _radio(identifier[, domRelation]) <input type="radio" name="name" id="id" value="value"> id, name, value, className, index _radio("id");
Sahi Pro
66
API HTML Identifier Example API HTML Identifier Example API HTML Identifier Example API HTML Identifier Example API HTML Identifier Example
_submit(identifier[, domRelation]) <input type="submit" name="name" id="id" value="value"> <button type="submit" name="name" id="id">value</button> value, name, id, className, index (sahiText: valid for <button/>) _submit("value"); _textbox(identifier[, domRelation]) <input type="textbox" name="name" id="id" value="value"> name, id, index, className _textbox("name"); _reset(identifier[, domRelation]) <input type="reset" name="name" id="id" value="value"> <button type="reset" name="name" id="id"> value</button> value, name, id, index, className (sahiText: valid for <button/>) _reset("value"); _file(identifier[, domRelation]) <input type="file" name="name" id="id" value="value"> name, id, index, className _file("name"); _imageSubmitButton(identifier[, domRelation]) <input type="image" name="name" id="id" value="value" alt="alt" title="title" src="/images/file.gif"> title|alt, name, id, fileName, index, className _imageSubmitButton("title"); _imageSubmitButton("file.gif"); _select(identifier[, domRelation]) <select name="name" id="id"></select> name, id, index, className _select("id");
Sahi Pro
67
_option(identifier[, domRelation]) <option id="id" value="value">text</option> sahiText, value, id, index _option(selectElement, identifier) has been phased out since 2010-06-10. Please use _option(identifier, _in(selectElement)) instead. _option("text"); _option("text",_in(_select("selectedId"))); _textarea(identifier[, domRelation]) <textarea name="name" id="id">text</textarea> name, id, index, className _textarea("name"); _hidden(identifier[, domRelation]) <input type="hidden" name="name" id="id" value="value"> name, id, className, index _hidden("id");
Accessors of HTML5 Form elements API HTML Identifier Example API HTML Identifier Example API HTML Identifier Example _timebox(identifier) <input type="time" name="name" id="id" value="value"/> name, id, index, className _timebox("name"); _datebox(identifier) <input type="date" name="name" id="id" value="value"/> name, id, index, className _datebox("name"); _datetimebox(identifier) <input type="datetime" name="name" id="id" value="value"/> name, id, index, className _datetimebox("name");
Sahi Pro
68
API HTML Identifier Example API HTML Identifier Example API HTML Identifier Example API HTML Identifier Example API HTML Identifier Example API HTML Identifier Example
_datetimelocalbox(identifier) <input type="datetime-local" name="name" id="id" value="value"/> name, id, index, className _datetimelocalbox("name"); _weekbox(identifier) <input type="week" name="name" id="id" value="value"/> name, id, index, className _weekbox("name"); _monthbox(identifier) <input type="month" name="name" id="id" value="value"/> name, id, index, className _monthbox("name"); _numberbox(identifier) <input type="number" name="name" id="id" value="value"/> name, id, index, className _numberbox("name"); _rangebox(identifier) <input type="range" name="name" id="id" value="value" min="min" max ="max"/> name, id, index, className _rangebox("name"); _telephonebox(identifier) <input type="tel" name="name" id="id" value="value"/> name, id, index, className _telephonebox("name");
Sahi Pro
69
API HTML Identifier Example API HTML Identifier Example API HTML Identifier Example
_emailbox(identifier) <input type="email" name="name" id="id" value="value"/> name, id, index, className _emailbox("id"); _urlbox(identifier) <input type="url" name="name" id="id" value="value"/> index, name, id _urlbox("name"); _searchbox(identifier) <input type="search" name="name" id="id" value="value"/> Index, name, id _searchbox("name");
Accessors of parent DOM Nodes All parent node accessors can take two parameters: element: The element whose parent node needs to be found occurrence: The nth parent. 1 is the immediate parent. For example, In <div id="div2"><span><div id="div1"><a href="">aLink</a></div></span></div> _parentNode(_link("aLink"), "DIV", 1); points to div1 _parentNode(_link("aLink"), "DIV", 2); points to div2 API HTML Example _parentNode(element, tagname[, occurrence]) <div id="id"><a href="http://u/r/l">aElement</a></div> _parentNode("DIV", _link("aElement")); may return _div("id");
Sahi Pro
70
_parentRow(element[, occurrence]) <tr><td>aCell</td></tr> _parentRow(_cell("aCell")); _parentTable(element[, occurrence]) <table class="api"> <tr><td>aCell</td></tr></table> _parentTable(_cell("aCell"));
Accessors of IFrames and Rich Text Editors based on IFrames in editable mode API HTML Identifier Example API HTML Identifier Example _rte(identifier) <iframe src="" name="name" id="id" ></iframe> name, id, index _rte("id"); _iframe(identifier) <iframe src="" name="name" id="id" ></iframe> name, id, index _iframe("id");
Generic accessors API HTML Identifier Notes Example _byId(id) <anytag id="id" ></anytag> id This can be used for any tag with an id. This API does not accept regular expressions or indexes. _byId("id");
Sahi Pro
71
API HTML Identifier Notes Example API HTML Identifier Example API Identifier
_byText(identifier, tagName) <anytag>text</anytag> text This can be used for any tag with text. _byText("text"); _byClassName(identifier, tagName[, domRelation]) <anytag class="className">text</anytag> className _byClassName("text"); _byXPath(xpath[, domRelation]) xpath expression as string . This is a convenience method for people moving from Selenium or other tools to Sahi. XPaths are natively enabled on Firefox. For browsers like Internet Explorer which do not have support for XPath use Javascript-XPath. Copy the contents of javascript-xpath-latest.js and save the contents to sahi/htdocs/spr/ext/javascriptxpath/javascript-xpath.js and there is a README.txt which has these instructions This file is under its own MIT license and is not part of Sahis code base
Notes
Example
_byXPath("//table[3]//tr[1]/td[2]"); _byXPath("//tr[1]/td[2]", _in(_table(2))); _accessor(string) This API just evaluates the string and returns a dom object. This API is not too useful. _accessor("document.formName.elementName");
Browser popups: Alerts, Confirms and Prompts Browser popus are of three types: Alert Box Confirm Box Prompt Box Sahi does not display browser popups during playback. However, the content from these popups is made available so that assertions can be made on it. Sahi Pro Tyto Software Pvt. Ltd. 72
_lastAlert() Returns the message displayed in the last javascript alert popup. Consider this HTML snippet: <input type="button" onclick="alert('abc')"value="Click Me"> The following test will click the button and assert that abc was alerted. _click(_button("Click Me")); _assertEqual("abc", _lastAlert());
_lastConfirm() Returns the message displayed in the last javascript confirm popup _lastConfirm returns the text of the last confirm which occured. Consider this HTML snippet: <input type="button" onclick="confirm('Did you get it?')"value="Click Me"> The following test will click the button and assert that Did you get it? was confirmed. _click(_button("Click Me")); _assertEqual("Did you get it?", _lastConfirm());
_lastPrompt() Returns the message displayed in the last javascript prompt popup. _lastPrompt returns the text of the last prompt which occured. Consider this HTML snippet: <input type="button" onclick="prompt('Enter Name')"value="Click Me"> If a user enters Ram in the prompt box, the following test will click the button and assert that Ram was entered. _click(_button("Click Me")); _expectPrompt("Enter name", "Ram"); _assertEqual("Ram", _lastPrompt()); Since the prompt is not displayed during playback, the _expectPrompt API should be used to enter value in the prompt. Refer to _expectPrompt for more details.
Sahi Pro
73
Utility functions to access properties of elements API cssProperty Notes HTML Example API Notes Example _style(element, cssProperty) Any property declared via CSS i.e., height, background-color etc Returns the value of the style property for that element. <td style="background-color:red">cell text</td> _style(_cell("cell text"), "background-color"); returns rgb(255, 0, 0) _cookie(cookieName) Returns the value of the cookie with cookieName. _cookie("SESSID"); This may return 44159b7fdf524e97015f1982e65990d2 _position(element) Returns the array with the elements x, y coordinate in pixels. _position(_div("id")); If the div is present present at (100, 180), _position(el) will return [100, 180]. _getText(element) <div id=divId>This is some <b>bold</b> <a href=#>link</a></div> Returns the innerText or textContent of an element. _getText(_div("divId")); will return This is some bold link _getCellText(cellElement) <td id=dataId>cell text</td> Returns the innerText or textContent of an element. Same as _getText _getCellText(_cell("dataId")); _getSelectedText(selectElement) Returns the text of the selected option in a <select>tag Consider this HTML snippet: <select id="age"><option>21</option><option>32</option></select> If 32 is the selected option, then _getSelectedText(_select("age")); may return 32
API HTML Notes Example API HTML Notes Example API Notes Example
Sahi Pro
74
_rteHTML(element) Returns the html inside a rich text editor. _rteHTML(_rte("rteId")); will return the rich text editors contents. _rteText(element) Returns the text inside a rich text editor. _rteText(_rte("rteId")); will return the rich text editors text content (without the html formatting). _isVisible(element) Returns true if the HTML element is visible on the user interface. This API uses the CSS visibility (style.visibility.hidden) or display property (style.display.none) to determine the visibility of an element. Can be used to assert if a mouse over menu has appeared or not. _isVisible(_div("divId")); _exists(element) Returns true if the HTML element exists. Same as checking element != null. _exists(_link("Login")); _containsText(element, text) <div id="divId">some text displayed here</div> Returns true if the element contains the given text _containsText(_div("divId"), "some"); _containsHTML(element, html) <div id="divId">some <b>text</b></div> Returns true if the element contains the given html _containsHTML(_div("divId"), "<b>text</b>") ; returns true _contains(parentElement, childElement) <div id="id"><a href="http://u/r/l">aElement</a></div> Returns true if childElement is a child of parentElement _contains(_div("id"), _link("aElement")); returns true
API Notes
Example API Notes Example API HTML Notes Example API HTML Notes Example API HTML Notes Example
Sahi Pro
75
Marker functions to show DOM relation API Notes _in(element) Refer DOM Relations
API Notes
Marker functions to show Positional relation API Notes Example _xy(element, x, y) Specifies the coordinates on element where the event is fired. _click(_xy(_button("id"), 10, 20)); clicks inside the button, 10px from the left and 20 pixels from the top. Negative values can be given to specify offset from right and bottom. _click(_xy(_button("id"), -5, -10)); clicks inside the button, 5px from the right and 10px from the bottom. API Notes _under(element) Refer Positional Relations
Sahi Pro
76
Mouse Actions API Notes Syntax _click(element, combo) Clicks the element. _click( element[, combo] ) element: HTML element to click combo (Optional): Any combo key; can be CTRL, SHIFT, ALT or META; Can also be two or more keys together like CTRL|SHIFT _click(_button("Click Me")); _click(_button("Click Me"), "CTRL"); // clicks with CTRL key pressed _click(_button("Click Me"), "CTRL|SHIFT"); // clicks with CTRL and SHIFT keys pressed clicksTest.sah
Example
Demo Script
_rightClick(element, combo) Right clicks on an element. _rightClick( element[, combo] ) element: HTML element to right click combo (Optional): Any combo key; can be CTRL, SHIFT, ALT or META; Can also be two or more keys together like CTRL|SHIFT _rightClick(_button("Right Click Me")); _rightClick(_button("Right Click Me"), "CTRL"); // clicks with CTRL key pressed _rightClick(_button("Right Click Me"), "CTRL|SHIFT"); // clicks with CTRL and SHIFT keys pressed clicksTest.sah
Example
Demo Script
Sahi Pro
77
_doubleClick(element, combo) Double clicks on an element. _doubleClick( element[, combo] ) element: HTML element to double click on combo (Optional): Any combo key; can be CTRL, SHIFT, ALT or META; Can also be two or more keys together like CTRL|SHIFT _doubleClick(_button("Double Click Me")); _doubleClick(_button("Double Click Me")); // doubleClicks with CTRL key pressed _doubleClick(_button("Double Click Me") "CTRL|SHIFT"); // doubleClicks with CTRL and SHIFT keys pressed clicksTest.sah _check(element) Checks the given checkbox or radio element. If already checked, this API does not do anything. _check( element ) element: element to be checked. Element should be a checkbox or radio element. _check("checkboxName"); _check("radioName"); checkbox.sah _uncheck(element) Unchecks the given checkbox. If already unchecked, this API does not do anything. _uncheck( element) element: element to be unchecked. Element should be a checkbox. _uncheck("checkboxName"); checkbox.sah
Example
Demo Script API Notes Syntax Example Demo Script API Notes Syntax Example Demo Script
Sahi Pro
78
_mouseOver(element, combo) Simulates a mouse over on the element. _mouseOver( element[, combo] ) element: HTML Element to hover over combo (Optional): Any combo key; can be CTRL, SHIFT, ALT or META; Can also be two or more keys together like CTRL|SHIFT _mouseOver(_button("Click Me")); _mouseOver(_button("Click Me"), "CTRL"); // mouseOver with CTRL key pressed _mouseOver(_button("Click Me"), "CTRL|SHIFT"); // mouseOver with CTRL and SHIFT keys pressed mouseEvents.sah _mouseDown(element, isRight, combo) Simulates a mouse down on the element. _mouseDown( element[, isRight, combo] ) element: HTML element to perform a mouse down on isRight (Optional): Set to true for a left-hand mouse combo (Optional): Any combo key; can be CTRL, SHIFT, ALT or META; Can also be two or more keys together like CTRL|SHIFT _mouseDown(_button("Mouse Down")); _mouseDown(_button("Mouse Down"),true); _mouseDown(_button("Mouse Down"), false, "CTRL"); //mouseDown with CTRL key pressed _mouseDown(_button("Mouse Down"), false, "CTRL|SHIFT"); //mouseDown with CTRL and SHIFT keys pressed mouseEvents.sah
Example
Example
Demo Script
Sahi Pro
79
_mouseUp(element, isRight, combo) Simulates a mouse up on the element. _mouseUp( element[, isRight, combo] ) element: HTML element to perform a mouse up on isRight (Optional): Should be true for a left-hand mouse combo (Optional): Any combo key; can be CTRL, SHIFT, ALT or META; Can also be two or more keys together like CTRL|SHIFT _mouseUp(_button("Mouse Down")); _mouseUp(_button("Mouse Down"),true); _mouseUp(_button("Mouse Down"), false, "CTRL"); //mouseUp with CTRL key pressed _mouseUp(_button("Mouse Down"), false, "CTRL|SHIFT"); //mouseUp with CTRL and SHIFT keys pressed mouseEvents.sah _simulateMouseEvent(element, type, isRight, isDouble, combo) Simulates any mouse event on an element. _simulateMouseEvent( element, type[, isRight, isDouble, combo] ) element: HTML element to trigger the mouse event on type: Mouse event type. Eg. mousedown, mouseup, mouseover, mousemove isRight (Optional): Should be true for a left-hand mouse isDouble (optional): Should be true for a double click. combo (Optional): Any combo key; can be CTRL, SHIFT, ALT or META; Can also be two or more keys together like CTRL|SHIFT _simulateMouseEvent(_button("Mouse Event"), "mousedown"); _simulateMouseEventXY(element, type, x, y, isRight, isDouble, combo) Simulates a mouse event on an element and triggers the event at (x, y) coordinates. The default coordinates are (0, 0) _simulateMouseEvent( element, type[, x, y, isRight, isDouble, combo] ) element: HTML element to trigger the mouse event on type: Mouse event type. Eg. mousedown, mouseup, mouseover, mousemove x: x coordinate to trigger the event from y: y coordinate to trigger the event from isRight (Optional): Should be true for a left-hand mouse isDouble (optional): Should be true for a double click. combo (Optional): Any combo key; can be CTRL, SHIFT, ALT or META; Can also be two or more keys together like CTRL|SHIFT _simulateMouseEventXY(_button("Mouse Event"), "mousedown", 10, 5);
Example
Example
Sahi Pro
80
_dragDrop(draggable, droppable, offsetX, offsetY) Drags elementToDrag and drops on elementToDropOn _dragDrop( draggable, droppable[, offsetX, offset] ) draggable: HTML element to be dragged droppable: HTML Element where the draggable will be dropped offsetX (Optional): X coordinate from where the drop event is triggered offsetY (Optional): Y coordinate from where the drop event is triggered _dragDrop(_image("item"), _byId("ShoppingCart")); This will drag the item and drop it in the shopping cart Drag and Drop is not a native event till HTML4. So events are synthesized in Sahi for some generic cases which may not work for every framework. (HTML5 has native drag drop capabilities). To fix this, you could write your own function using the various _mouseXXX APIs. For example, to dragDrop on a GWT grid, you may use: function gwtDragDrop($dragEl, $dropEl){ _mouseDown($dragEl); _mouseOver($dragEl); _mouseOver($dropEl); _mouseUp($dropEl); } gwtDragDrop(_span("drag me"), _span("drop on me")); For multi-window drag drops, the code may look something like this: function dragDropMultiwin($win1, $dragEl, $win2, $dropEl){ _selectWindow($win1); _mouseDown($dragEl); _mouseOver($dragEl); _selectWindow($win2); _mouseOver($dropEl); _mouseUp($dropEl); } dragDropMultiwin("window1", _span("drag me"), "window2", _span("drop on me")); Normally the drag event is triggered at coordinate (0, 0) of an element. If your element needs to be clicked somewhere in between, say 10px from left and 5px from top, use this example: _dragDrop(_xy(_image("item"),10,5), _byId("ShoppingCart"));
Example
Demo Script
dragDrop.sah
Sahi Pro
81
_dragDropXY(draggable, x, y, isRelative) Drags elementToDrag and drops it on the given x, y coordinates. _dragDropXY(draggable, x, y[, isRelative]) draggable: HTML Element to be dragged x: x coordinate of drop point on the page y: y coordinate of drop point on the page isRelative (Optional): Specifies whether the coordinates are relative to current position of draggable element. If _image("item") is located at coordinates (50, 150) _dragDropXY(_image("item"), 100, 300); will drag the item and drop it at the coordinate (100, 300) The end result is that the elements coordinates will be at (100, 300) _dragDropXY(_image("item"), 100, 300, true); will drag the item and drop it at the coordinate (50+100, 150+300) The end result is that the elements coordinates will be at (150, 450)
Example
Demo Script
dragDropXY.sah
Focus Actions API Notes Syntax Example Demo Script API Notes Syntax Example Demo Script _focus(element) Brings focus to element. _focus(element) element: Element to bring to focus _focus(_textbox("username")); focusTest.sah _removeFocus(element) Removes focus from element. _removeFocus(element) element: Element to remove focus from _removeFocus(_textbox("username")); focusTest.sah
Sahi Pro
82
_blur(element) Removes focus from element. _blur(element) element: Element to remove focus from _blur(_textbox("username")); focusTest.sah
Key Actions API Notes Syntax _keyPress(element, charInfo, combo) Simulates a keypress event for key with given charInfo on the element. _keyPress(element, charInfo[, combo]) element: HTML element to press the key on charInfo: character or character code or array of [keyCode, charCode] combo (Optional): ): Any combo key; can be CTRL, SHIFT, ALT or META; Can also be two or more keys together like CTRL|SHIFT _keyPress(_textbox("t2"), 'a'); //Set a in textbox _keyPress(_textbox("t2"), 97); //Set a in textbox _keyPress(_textbox("t2"), 'a', "ALT"); //Enter a with ALT key pressed keypress.sah _keyDown(element, charInfo, combo) Simulates a keydown event for key with given charInfo on the element. _keyDown(element, charInfo[, combo]) element: HTML element to invoke the keydown on charInfo: character or character code or array of [keyCode, charCode] combo (Optional): Any combo key; can be CTRL, SHIFT, ALT or META; Can also be two or more keys together like CTRL|SHIFT _keyDown(_textbox("t2"), 'a'); _keyDown(_textbox("t2"), 97); _keyDown(_textbox("t2"), 'A', "SHIFT"); _keyDown(_textbox("t2"), [13,0]); //Press enter key google_search_dd.sah
Example
Example
Demo Script
Sahi Pro
83
_keyUp(element, charInfo, combo) Simulates a keyup event for key with given charInfo on the element. _keyUp(element, charInfo[, combo]) element: HTML element to invoke the keyup on charInfo: character or character code or array of [keyCode, charCode] combo (Optional): Any combo key; can be CTRL, SHIFT, ALT or META; Can also be two or more keys together like CTRL|SHIFT _keyUp(_textbox("t2"), 'a'); _keyUp(_textbox("t2"), 97); _keyUp(_textbox("t2"), 'A', "SHIFT"); _keyUp(_textbox("t2"), [13,0]); //Press enter key google_search_dd.sah
Example
Demo Script
Data Input Actions API Notes Syntax _setValue(element, text) Focuses on the element, types in the text and then removes focus from element. element can be a textarea or a textbox _setValue(element, value) element: HTML Form Element whose value needs to be set value: String value _setValue(_textbox("username"), "karthik"); _setValue(_textarea("address"), "Somewhere there"); _setValue(_password("password"), "secret"); textarea.sah
Example
Demo Script
Sahi Pro
84
_setSelected(element, option_identifier[, isMultiple]) Selects the option with option_identifier in select element. _setSelected ( element, option_identifier, isMultiple) element: HTML select element option_identifier: Options text, id or index; can also pass an array of options for multi-select isMultiple (Optional): true for multiselect _setSelected(_select("Age"), "28"); _setSelected(_select("color"), 1); // Selects the second option in a select box _setSelected(_select("color"), red); // Selects red in a multiselect box _setSelected(_select("color"), blue, true); // Selects blue also in the multiselect box _setSelected(_select("color"), [red, blue]); // Unselects previous and selects red and blue in a multiselect box _setSelected(_select("color"), [1,2,3]); // Unselects previous and selects the second, third and fourth options in a multiselect box _setSelected(_select("color"), [green, yellow], true); // Keeps previous options selected and selects green and yellow also select.sah
Example
Demo Script
Sahi Pro
85
_setFile(element, filePath) Prepares the form to set file at filePath. _setFile(element, filePath [, actionURL]) element: HTML Form File Element whose value needs to be set filePath: Path of the file to be uploaded. actionURL (Optional): The form action URL to which the file is submitted. This is an optional parameter. Use it in cases where the forms action URL is changed on setting the file. By default, it uses the forms current action URL. _setFile(_file("id"), "C:\\abc\\efg.jpg"); _setFile(_file("id"), "C:\\abc\\efg.jpg", "formSubmit.jsp"); Note that _setFile works in a roundabout way. It is not handled at the browser level. It is handled at the proxy. So you will not see the file input box being populated with your desired filename. But when the form is submitted, the proxy will add the correct file to the request before it sends it to your web server. But if there are javascript checks before form submit to see if the filename is non-empty, then the script will not work as desired. If there are javascript validations on the file field, you can try this hack. Before submitting the file, change the fields type to text, and then set its value like this
Example
// set the file _setFile(_file("file"), "scripts/demo/uploadme.txt"); // Change the "type" attribute of file field if (_isIE()){ _call(_file("file").outerHTML = _file("file").outerHTML.replace(/type=file/, "type=text")); }else{ _call(_file("file").type = "text"); } // Set the value into the textbox _setValue(_textbox("file"), "scripts/demo/uploadme.txt"); Demo Script API Notes Syntax fileUpload.sah _rteWrite(iframe, text) Writes text into a rich text editor based on content-editable iframe _rteWrite(iframe, text) iframe: editable iframe text: text to insert into the iframe _rteWrite(_rte("editorId"), "Welcome Karthik"); Iframes in design mode (contentEditable true) are considered Rich Text Editors (RTE) by Sahi.
Example
Sahi Pro
86
_type(element, text) Types the text into the element. Different from _setValue. _type does not bring or remove focus from element. Rarely used. _type(element, text) element: HTML element to type into text: text to be inserted _type(_textbox("a"), "text input");
Example
Assertions The following APIs will log messages into the report on assertion failure ONLY DO NOT USE THIS IN AN IF CONDITION as it does not return any value, and throws an exception if the expected and actual values are not equal. API Notes Syntax _assertEqual(expected, actual, message) Asserts that expected and actual are equal, else logs the message. _assertEqual( expected, actual, message ) expected: expected value actual: actual value message: Message to be written to logs if the expected and actual values are not equal _assertEqual("abc", "abc", "Some Log Message"); This does nothing _assertEqual("abc", "def", "Some Log Message"); This throws exception and writes Some Log Message to logs. _assertNotEqual(expected, actual, message) Asserts that expected and actual are NOT equal, else logs the message. _assertNotEqual( expected, actual, message ) expected: expected value actual: actual value message: Message to be written to logs if the expected and actual values are not equal _assertNotEqual("abc", "def", "Some Log Message"); This does nothing _assertNotEqual("abc", "abc", "Some Log Message"); This throws exception and writes Some Log Message to logs.
Example
Example
Sahi Pro
87
_assertNotNull(object, message) Asserts that the object is NOT null, else logs the message. _assertNotNull( object, message ) object: Any object message: Message to be written to logs if the expected and actual values are not equal _assertNotNull("abc"); This does nothing _assertNotNull(null, "Some Log Message"); This throws exception and writes Some Log Message to logs. _assertNull(object, message) Asserts that the object is null, else logs the message. _assertNull( object, message ) object: Any object message: Message to be written to logs if the expected and actual values are not equal _assertNull(null); This does nothing _assertNotNull("abc", "Some Log Message"); This throws exception and writes Some Log Message to logs. _assertTrue(condition, message) Asserts that the condition is true, else logs the message. _assertTrue( condition, message ) condition: Boolean expression message: Message to be written to logs if the expected and actual values are not equal _assertTrue(1==1); This does nothing _assertTrue(1==2, "Some Log Message"); This throws exception and writes Some Log Message to logs.
Example
Example
Example
Sahi Pro
88
_assert(condition, message) Asserts that the condition is true, else logs the message. Same as _assertTrue _assert( condition, message ) condition: Boolean expression message: Message to be written to logs if the expected and actual values are not equal _assert (1==1); This does nothing _assert (1==2, "Some Log Message"); This throws exception and writes Some Log Message to logs. _assertNotTrue(condition, message) Asserts that the condition is NOT true, else logs the message. _assertNotTrue( condition, message ) condition: Boolean expression message: Message to be written to logs if the expected and actual values are not equal _assertNotTrue(1==2); This does nothing _assertNotTrue(1==1, "Some Log Message"); This throws exception and writes Some Log Message to logs. _assertFalse(condition, message) Asserts that the condition is false, else logs the message. _assertFalse( condition, message ) condition: Boolean expression message: Message to be written to logs if the expected and actual values are not equal _assertFalse(1==2); This does nothing _assertFalse(1==1, "Some Log Message"); This throws exception and writes Some Log Message to logs.
Example
Example
Example
Sahi Pro
89
_assertExists(object, message) Asserts that the object is not null, else logs the message. _assertExists( object, message ) object: Any object message: Message to be written to logs if the expected and actual values are not equal _assertExists(_link("Back to form")); This does nothing _assertExists(null, "Some Log Message"); This throws exception and writes Some Log Message to logs. _assertNotExists(object, message) Asserts that the object does not exist (is null), else logs the message. _assertNotExists( object, message ) object: Any object message: Message to be written to logs if the expected and actual values are not equal _assertNotExists(null); This does nothing _assertNotExists(_link("Back to form"), "Some Log Message"); This throws exception and writes Some Log Message to logs. _assertContainsText(expectedText, object, message) Asserts that the object contains the expectedText, else logs the message. _assertContainsText( expectedText, object, message ) expectedText: Text expected to be present. This can be replaced with a regular expression. object: Any object message: Message to be written to logs if the expected and actual values are not equal _assertContainsText("Invalid Login", _div("login_section"), "Text was not present"); _assertContainsText(/[Ii]nvalid/, _div("login_section"), "Text was not present"); _assertContainsText("Invalid Login", _div("login_section")); _assertContainsText(/[Ii]nvalid/, _div("login_section"));
Example
Example
Example
Sahi Pro
90
_assertNotContainsText(expectedText, object, message) Asserts that the object does not contain the expectedText, else logs the message. _assertNotContainsText( expectedText, object, message ) expectedText: Text expected not to be present. This can be replaced with a regular expression. object: Any object message: Message to be written to logs if the expected and actual values are not equal _assertNotContainsText("Invalid Login", _div("login_section"), "Text was present"); _assertNotContainsText(/[Ii]nvalid/, _div("login_section"), "Text was present"); _assertNotContainsText("Invalid Login", _div("login_section")); _assertNotContainsText(/[Ii]nvalid/, _div("login_section")); _assertEqualArrays(expected, actual, message) Asserts that expected and actual arrays are equal, else logs the message. _assertEqualArrays( expected, actual, message ) expected: expected array actual: actual array message: Message to be written to logs if the expected and actual values are not equal _assertEqualArrays([1,2,3],[1,2,3]); This does nothing _assertEqualArrays([1,2,3],[1,2,4] , "Some Log Message"); This throws exception and writes Some Log Message to logs. NOTE: This is internally called by _assertEqual if expected and actual are arrays
Example
Example
Utility actions API Notes Syntax _navigateTo(url, forceReload) Navigates to the given url. _navigateTo( url, forceReload ) url: URL to navigate to. forceReload: when set to true, refreshes the page. _navigateTo("http://sahi.co.in"); _navigateTo("http://sahi.co.in", true);
Example
Sahi Pro
91
_closeWindow() Closes the current window. This will work ONLY for popups. _closeWindow() _popup("popWin")._closeWindow(); _log(message, logLevel) Logs message into the playback logs. _log( message, logLevel ) message: Message to log type: where type can be success, failure, error, info, custom(1 - 5) _log("Message", "failure"); Output: Message _log("Message ", "success"); Output: Message _log("Message ", "error"); Output: Message _log("Message ", "info"); Output: Message _log("Message ", "custom"); Output: Message _log("Message ", "custom1"); Output: Message _log("Message ", "custom2"); Output: Message _log("Message ", "custom3"); Output: Message _log("Message ", "custom4"); Output: Message _log("Message ", "custom5"); Output: Message _wait(maxTime, condition) Waits for timeInMilliseconds ms or till the condition is satisfied on the browser, whichever is sooner. _wait( maxTime, condition ) maxTime: Time in milliseconds after which execution will resume condition: (Optional) Condition which when satisfied will resume execution _wait(1000); Will stop execution for a second _wait(1000, _byId("ajaxy").innerHTML!=""); Will wait till div by id ajaxy is populated or one second, whichever occurs sooner wait_for.sah
Example
Example
Demo Script
Sahi Pro
92
_call(javascriptSnippet) Executes the javascriptSnippet on the browser, instead of in the Rhino engine. _call( javascriptSnippet ) javascriptSnippet : Javascript to be invoked in on the browser. <browser> function toggleTreeWidget(){ // some javascript to toggle a tree widget } </browser> _call(toggleTreeWidget()); _call(location.href = "xxx");
Note: To fetch a value from a function on the browser and store it a variable in script, use _set <browser> function getRowCount(){ return _table("t1").rows.length; } </browser> var $count; _set ($count, getRowCount()); // Use $count _alert($count); Important: Sahi will evaluate the content in <browser> on the browser instead of the rhino engine. _call should be used sparingly and only if none of the inbuilt Sahi Browser Action APIs work.
Sahi Pro
93
API Notes
_set( $variableName, value ) _set is used to fetch the value of a page dependent variable (something that is part of the browser page) and store it in a Sahi variable. You would need this to access Javascript attributes not already exposed by Sahis APIs. _set( $variableName, value ) $variableName: variable to assign the value to value: value to assign. Note that the value should not be a javascript object which has attributes which reference itself. If we wish to get the href of a link, var $href; _set($href, _link("my link").href); // store // you may do other actions or navigate to other pages _assertEqual("http://sahi.co.in", $href); //use Note that there is no Sahi API to retrieve the href property directly. For retrieving text using _getText, _set is not required. var $text = _getText(_link("linkId")); Another example with a browser function: <browser> function getRowLength(){ return _table("t1").rows.length; } </browser> var $count=0; _set ($count, getRowLength()); _alert($count);
Syntax
Example
Sahi Pro
94
_eval(string) Evals the string on the browser, instead of in the Rhino engine. _eval(string) string: String to evaluate _eval("document.form1.complicatedWidget.click()"); Note: _call is different from _eval. _eval takes a string. _call(toggleTreeWidget()); This is the same as _eval("toggleTreeWidget()");
_callServer(cmd, qs) Calls server side code which cannnot be executed by javascript on the browser. _callServer(cmd, qs) cmd: String command of the form className_methodName qs: QueryString to be made available in the invoked method Below is an implementation of writing debug messages to the console. Create this class: package net.sf.sahi.ext; import net.sf.sahi.request.HttpRequest; public class Debug { public void toOut(HttpRequest request) { String msg = request.getParameter("msg"); System.out.println(msg); } } Add it to Sahis classpath: Look at Adding jars to Sahis classpath Call this from your script: _callServer("net.sf.sahi.ext.Debug_toOut", "msg=SomeMessage"); This will write SomeMessage on the console where sahi was started. Since Sahi V2, these actions can directly be performed by calling java classes from javascript through Rhino.
Example
Sahi Pro
95
API Notes
_savedRandom( id, min, max ) Stores a random number against an id. First invocation: Returns a random number between min and max Subsequent calls with the same id: Returns the number that it had returned the first time for the given id. _savedRandom( id, min, max ) id: Any string min: Lower limit for the number generated max: Upper limit for the number generated _savedRandom("login", 100, 200); returns a random number between 100, 200; say 145. _savedRandom("login", 100, 200); will return 145, since it was saved against the id "login". The min and max are redundant here. _savedRandom("login"); will also return 145. _resetSavedRandom(key) Resets the random number associated with key, to another random number. From Sahi V2, random numbers can be generated using _random and stored as simple variables. _resetSavedRandom( key ) key: Id of the _savedRandom that needs to be reset _savedRandom("a", 10, 30); // returns a random number, say 23 _savedRandom("a", 10, 30); // returns 23 _savedRandom("a"); // returns 23 _resetSavedRandom("a"); _savedRandom("a"); // returns null _savedRandom("a", 10, 30); // returns another random number _random(max) Returns a random number between 0 and max _random( max ) max: Upper limit for the number generated _random(10); may generate any number between 0 and 10.
Syntax
Example
API Notes
Syntax Example
Sahi Pro
96
API Notes
_setGlobal(key, value) Stores the value in key for retrieval. The value persists across tests in a suite, if suite.global_variables is true in sahi.properties. _setGlobal( key, value ) key: identifier value: value associated with the key _setGlobal("userid1", _textbox("user").value); _getGlobal (key) Gets a previously stored variable whose scope will span a session. Globals are used for persisting variables across multiple web pages. _getGlobal ( key ) key: String identifying a global variable _setGlobal("name", "Ram"); _getGlobal("name"); // will return "Ram" _collect(apiType, id, inEl) Collects all elements of a particular type and stores them in an array. _collect(apiType, id[, inEl]) apiType: The type of API to collect id: A common identifier inEl (Optional): Parent element containing the elements to collect. var $els = _collect ("_link", "/group 1/", _in(_div("div1"))); $els is an array of all links containing the text group 1. _assertEqual("group 1 link3", _getText($els[0])); collect.sah _count(apiType, id, inEl) Counts all elements of a particular type and stores them in a variable. _count(apiType, id, inEl) apiType: The type of API to count id: A common identifier inEl (Optional): Parent element containing the number of elements to count. var $c = _count ("_link", "/group 1/"); $c may have a count of all links containing the text, group 1. _assertEqual(5, $c); collect.sah
Syntax
Example
Example
Demo Script
Sahi Pro
97
Actions to mock out particular URLs 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. We can add a mock by specifying this to our script. _addMock("www[.]adserver[.]com", "sahi.ext.MyCustomMock_filterAds"); Whenever Sahi encounters a URL request which matches www[.]adserver[.]com It will delegate the response handling to sahi.ext.MyCustomMocks filterAds method. One can call any classs 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. This response uses template at sahi/htdocs/spr/simpleMock.htm. One can modify this to show a generic mock response. By default this response just shows the mocked url. For images, one can use _mockImage, which is the same as _addMock except that it by default calls net.sf.sahi.command.MockResponder.mockImage(HttpRequest) which returns a simple image at sahi/htdocs/spr/mock.gif API Notes Syntax _addMock(pattern[, clazz_method]) Forces the proxy to process certain patterns of urls differently. If clazz_method is not specified, sends back a simple HTML blank page. _addMock(pattern[, clazz_method]) pattern: pattern to match clazz_method: method to send the response to _addMock("www[.]adserver[.]com", "sahi.ext.MyCustomMock_filterAds"); mock.sah
Sahi Pro
98
_mockImage(pattern[, clazz_method]) Similar to _addMock, but by default sends back an image. _mockImage(pattern[, clazz_method]) pattern: pattern to match clazz_method: method to send the response to _mockImage("www[.]adserver[.]com", "sahi.ext.MyCustomMock_filterAds"); _removeMock(pattern) Removes the mock behavior added via _addMock or _mockImage for that pattern. _removeMock(pattern) pattern: pattern to match _removeMock(".*sahi[.]co[.]in.*"); mock.sah
Sahi Pro
99
Actions to set expectations for javascript confirms and prompts API Notes _expectConfirm(message, boolean) Sets an expectation such that when a javascript confirm with given message appears, based on the boolean value, OK or Cancel will be processed. Should be used before the statement that triggers the confirm dialog. _expectConfirm( message, boolean ) message: The visible text on the confirm dialog boolean: Expected boolean return value. _expectConfirm("Some question?", true); Here, ok will be processed Javascript calls to confirm( msg ) are mocked out by Sahi so that it does not stop 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("Some question?", 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(); Demo Script API Notes confirm.sah _expectPrompt(message, text) Sets an expectation such that when a javascript prompt with given message appears, the given text is populated. Should be included before the statement that triggers a prompt. _expectPrompt( message, text ) message: The visible text on the prompt dialog text: Input value _expectPrompt("Some prompt?", "abc"); This will make the prompt return abc and can be accessed with _lastPrompt(); 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. If there was no expectation set, Sahi will return . prompt.sah
Syntax
Example
Syntax
Example
Demo Script
Sahi Pro
100
API Notes Syntax Example Demo Script API Notes Syntax Example Demo Script API Notes Syntax Example Demo Script API Notes Syntax Example Demo Script
_clearPrintCalled() resets the value of _printCalled _clearPrintCalled() _clearPrintCalled(); print.sah _clearLastAlert() Clears the value returned by _lastAlert() _clearLastAlert() _clearLastAlert(); alert.sah _clearLastPrompt() Clears the value returned by _lastPrompt() _clearLastPrompt() _clearLastPrompt(); prompt.sah _clearLastConfirm() Clears the value returned by _lastConfirm() _clearLastConfirm() _clearLastConfirm(); confirm.sah
Actions used for debugging API Notes Syntax Example _highlight(element) Highlights an element with a red border. Use only for debugging. _highlight(element) element: HTML element to highlight _highlight(_div("Average")); This may look like this Average
Sahi Pro
101
API Notes Syntax Example API Notes Syntax Example API Notes Syntax Example API Notes Syntax Example API Notes Syntax
_alert(message) Brings up a javascript alert with given message. Use only while debugging. _alert(message) message: message to show in alert _alert("Some message?"); _confirm(message) Brings up a javascript confirm with given message. Use only while debugging _confirm(message) message: message to show in confirm box _confirm("Do you wish to continue?"); _debug(message) Prints the message on to the console for debugging purposes. _debug(message) message: Message to print on the console _debug("Some message"); _debugToErr(message) Prints the message on to the error stream for debugging purposes. _debugToErr(message) message: Message to print _debugToErr("Some message"); _debugToFile(message, filePath) Prints the message into a file for debugging purposes. _debugToFile(message, filePath) message: Message to print filePath: Path of the file _debugToFile("Some message", "C:/errors.txt");
Example
Sahi Pro
102
Toggle KeepAlive Actions API _enableKeepAlive() Notes Syntax Example Turns on Keep-Alive. It is used in conjunction with _disableKeepAlive() on pages which hang because of flash objects or applets. _enableKeepAlive() _disableKeepAlive(); _call(loadPageWithFlashWhichHangsOtherwise()); _enableKeepAlive(); _disableKeepAlive() Turns off Keep-Alive. It is used in conjunction with _enableKeepAlive() on pages which hang because of flash objects or applets. _disableKeepAlive() _disableKeepAlive(); _call(loadPageWithFlashWhichHangsOtherwise()); _enableKeepAlive();
Cookie related actions API _createCookie(name, value, days) Notes Syntax Creates a cookie with name and value which will expire in given days. _createCookie(name, value, days) name: Name of the cookie value: Value to be stored in the cookie days: Number of days till expiry _createCookie("__login__sessid", "4rf6thbsk8t234hdi5673", 4); This will create a cookie called __login__sessid valid for 4 days _deleteCookie(name) Deletes cookie with given name. _deleteCookie(name) name: Name of the cookie _deleteCookie("__login__sessid"); may delete a cookie with the name __login__sessid
Example
Sahi Pro
103
Additionally, Sahi lets a user view all the cookies that are set during a session in a web application. This is available in http://domain.com/_s_/dyn/Cookies_showAll
Download related actions Sahi handles file downloads by silently downloading files into sahi/temp/download folder. The last downloaded file can be manipulated by the following APIs. Note that a _wait() statement may be required before _saveDownloadedAs in case the file is big and takes a lot of time to download. Sahis proxy detects file downloads, and automatically saves them to sahi/userdata/temp/download directory. Sahi also adds the sessionId to the file name, so that multiple simultaneous tests do not overwrite each others files. So if you were clicking on a download link which downloads a setup.exe file, this is how Sahi will handle it. 1) Click on download link 2) Sahi detects that it is a downloadable file, based on its MimeType and Content-Disposition headers. It then downloads and saves the file into sahi/userdata/temp/download/ after renaming it to something like: sahi_0384a26207e6104f5f08868032bd170de76d__setup.exe 3) Once the file is downloaded Sahi exposes the original name of the file (setup.exe) through the API: _lastDownloadedFileName() 4) Another API, _saveDownloadedAs, allows the file to be renamed and copied over to a convenient directory for you to work on. 5) API: _clearLastDownloadedFileName clears out the _lastDownloadedFileName() so that further files can be downloaded and worked upon. Sahi Pro Tyto Software Pvt. Ltd. 104
More information: Sahi detects that a file is to be downloaded, based on 1. content type (configurable via sahi/userdata/config/download_contenttypes.txt) 2. The Content-Disposition: attachment header 3. Whether the URL is configured in sahi/userdata/config/download_urls.txt If you see a file download dialog during playback, do the following: 1. Check if the download URL follows a specific pattern. If yes, add the pattern of the URL to download_urls.txt For example, if your download url is http://mysite.example.com/export_doc.jsp?id=12318812 , add .export_doc[.]jsp. to download_urls.txt 2. If there are multiple files that are to be downloaded, and they all are of a particular contenttype, add the content type to download_contenttypes.txt 3. If your file download response always has content-disposition as attachment, you can tell sahi to download them by default by setting download.download_if_contentdisposition_is_attachment=true in sahi/userdata/config/userdata.properties
API Notes Syntax Example Demo Script API Notes Syntax Example Demo Script
_saveDownloadedAs(filePath) Saves the file which was downloaded into sahi/temp/folder into the given filePath _saveDownloadedAs(filePath) filePath: Path where the file should be saved _saveDownloadedAs("c:/path/myfile.txt"); save_as.sah _clearLastDownloadedFileName() Clears the _lastDownloadedFileName (so that new files downloaded with the same fileName can be asserted) _clearLastDownloadedFileName() _clearLastDownloadedFileName(); save_as.sah
Sahi Pro
105
Miscellaneous APIs
Functions available on browser and on proxy API Notes Example API Notes Example API Notes _scriptName() Returns the name of the current script _scriptName(); may return keypress.sah _scriptPath() Returns the path of the current script _scriptPath(); may return C:/keypress.sah _popup(identifier) Returns a handle to the window. The identifier can be a regular expression. _popup() is used as a prefix to statements which need to be executed on another window. _popup( identifier ) identifier: windowName, windowTitle _popup("popWin")._click(_link("Click me")); _popup(/popWin.*/)._click(_link("Click me")); _popup("Window Title")._click(_link("Click me")); popup_title.sah _selectWindow(popupIdentifier) Sets the given window as context for the following Sahi statements. The identifier can be a regular expression. This API helps make scripting easier when most actions are performed on a popup window. _selectWindow( popupIdentifier ) popupIdentifier: windowName, windowTitle; if left blank, it chooses the base window _selectWindow("popWin"); //select popWin //further statements will be performed on popWin _click(_link("Click me"));// will click on popWin _selectWindow(); // select base window // further statements will be performed on base window _click(_button("Finished")); // clicks on base window; popup_title.sah
Syntax Example
Syntax
Example
Demo Script
Sahi Pro
106
_sessionInfo() Returns information of the current session. The object has attribures: isRecording isPlaying isPaused sessionId _sessionInfo(); _suiteInfo() Returns information of the current session. _suiteInfo(); _userDataDir() Returns absolute path to userdata directory. _userDataDir(); may return C:/sahi_pro/userdata/ _userDataPath(relativePath) Returns absolute path to userdata directory, given a relative path. _userDataPath("scripts"); may return C:/sahi_pro/userdata/scripts/ _lastDownloadedFileName() Returns the name of the last downloaded file name. _assertNull(_lastDownloadedFileName()); // nothing so far _click(_link("download")); // click on download link _assertEqual("setup.exe", _lastDownloadedFileName()); // check if downloaded _saveDownloadedAs("c:/path/myfile.txt"); // save to another path _clearLastDownloadedFileName(); // clear the variable _assertNull(_lastDownloadedFileName()); // check to see if cleared.
Sahi Pro
107
API Notes
_setStrictVisibilityCheck(boolean) This API is useful in cases where widgets are dynamically created at multiple locations but only one of them is visible at any given time. During recording Sahi can be forced into either mode by choosing Strict Visibility On or Strict Visibility Off from the Other Actions: dropdown. Make sure you Append to Script to add it to the recorded script
Example
_setStrictVisibilityCheck(true); makes Sahi ignore elements which are not visible. _setStrictVisibilityCheck(false); makes sahi revert to original behavior of considering all elements in the DOM. strict_visible.sah
Demo Script
Sahi Pro
108
Functions available on proxy only API Notes Syntax _logException(exception) Exceptions are handled via regular javascript try catch blocks since Sahi V2. try{ // sahi statements }catch(exception) { // Corrective action _logException( exception ); // Can print exact source of error in log // Can throw the same or another exception } exception: exception to log Corrective Action: try{ _click(_link("does not exist")); }catch(e) { _log("Exception occured"); // simple logging. no failure _click(_link("linkByHtml")); // Corrective action } Corrective Action and Log the Exception Message: try{ _click(_link("does not exist")); }catch(e) { _click(_link("linkByHtml")); // Corrective action _logException(e); // Logs the exception, but does not fail } API Notes Example API Notes Example _stopOnError() Makes the script stop if an error occurs. This is the default behavior. _stopOnError(); _continueOnError() Makes script continue inspite of errors. Can be turned off with _stopOnError() _continueOnError();
Example
Sahi Pro
109
_logExceptionAsFailure(exception) Exceptions are handled via regular javascript try catch blocks since Sahi V2 try{ // sahi statements }catch(exception){ // Corrective action _logExceptionAsFailure( exception ); // Can print exact source of error in log // Can throw the same or another exception } Corrective Action: try{ _click(_link("does not exist")); }catch(e){ _log("Exception occured"); // simple logging. no failure _click(_link("linkByHtml")); // Corrective action } Corrective Action, Log and then Fail: try{ _click(_link("does not exist")); }catch(e){ _click(_link("linkByHtml")); // Corrective action _logExceptionAsFailure(e); // Logs the exception, and fails, // and in the logs, points to the original line as source of failure. }
Example
Demo Script
log_exception_as_failure.sah
Sahi Pro
110
Recovery functions Sometimes it is necessary to do some corrective action in case a test fails half way through. This is different from try-catch because we do not want the script to continue; we just want the state of our system to be restored to a sensible point. The relevant APIs are: _setRecovery(fn); _removeRecovery(fn); Any function can be assigned to a script as a recovery function. Once set, if there is an error during execution, the recovery function will be called before the script stops.
API Notes
_setRecovery(fn) Sets fn as recovery function. The function will be called before the script exits, if and only if there is a failure in the script. It can be turned off with _removeRecovery(). _setRecovery( fn ) fn: recovery function _navigateTo("http://sahi.co.in/demo/"); function myRecoveryFn(){ _alert("In myRecoveryFn."); // This statement will be alerted in case of script error. } _setRecovery(myRecoveryFn); // Set the myRecoveryFn as recovery function. _click(_link("Link Test")); // Works normally _click(_link("Bad Link")); // This statement fails and causes myRecoveryFn to be called. _alert("done"); // This statement will not be called, because script failed in the last statement.
Syntax Example
Sahi Pro
111
_removeRecovery(fn) Removes any recovery function which was set via _setRecovery(fn). _removeRecovery(fn) fn: recovery function _navigateTo("http://sahi.co.in/demo/"); function myRecoveryFn(){ _alert("In myRecoveryFn."); // This statement will be alerted in case of script error. } _setRecovery(myRecoveryFn); // Set the myRecoveryFn as recovery function. _click(_link("Link Test")); // Works normally _click(_link("Bad Link")); // This statement fails and causes myRecoveryFn to be called. _alert("done"); // This statement will not be called, because script failed in the last statement. _removeRecovery(myRecoveryFn);
Working with databases Sahi has an API that will allow the user to connect to various databases using the _getDB API This API returns a sahiDB object which has two methods select(sql) used for select statements update(sql); used for update/delete/insert statements To start working with _getDB API, it is necessary to have the appropriate driver to connect to a database. This driver has to be present in Sahis external classpath. More info: Adding jars to Sahis classpath select( sql ): The result set that is returned by the select statement is a list of rows. Rows are accessible by index. For example: ID 1 2 3 NAME Kamalesh Arun Raja AGE 28 30 35
For this table, we have: var db = _getDB("oracle.jdbc.driver.OracleDriver", "jdbc:oracle:thin:@dbserver:1521:sid", "username", "password"); var $rs = db.select("select * from User");
Sahi Pro
112
$rs[0][NAME] may return Kamalesh $rs[0] may return the first row $rs[1][ID] may return 2 NOTE: The columns in a row are accessible by their column names (not column index). API Notes Syntax _getDB(driver, jdbcurl, username, password) Returns a DB object which can be used to query the database. _getDB is used to connect to a database. _getDB(driver, jdbcurl, username, password) driver: JDBC driver class jdbcurl: JDBC URL username: username to connect to the database password: password to connect to the database For table User ID NAME 1 Kamalesh 2 Arun 3 Raja AGE 28 30 35
Example
var db = _getDB("oracle.jdbc.driver.OracleDriver", "jdbc:oracle:thin:@dbserver:1521:sid", "username", "password"); var $rs = db.select("select * from User"); _assertEqual("2", $rs[1]["ID"]); _assertEqual("Kamlesh", $rs[0]["NAME"]); _assertEqual("28", $rs[0]["AGE"]); Looping through results: Here is an example which loops through the results, and calls a custom function. var db = _getDB("oracle.jdbc.driver.OracleDriver", "jdbc:oracle:thin:@dbserver:1521:sid", "username", "password"); var $rs = db.select("select * from User"); for (var $i=0; $i < $rs.length; $i++){ var $row = $rs[$i]; var $name = $row["NAME"]; var $age = $row["AGE"]; // pass name and age to your custom function like processNameAge processNameAge($name, $age); } Demo Script db.sah
You can also connect to an excel sheet with _getDB. Sahi Pro Tyto Software Pvt. Ltd. 113
On Windows, you could use the jdbc:odbc driver to access Excel. This does not need any extra jars. NOTE: On 64 bit windows, you need to download and install the 64 bit ODBC drivers (Download and install AccessDatabaseEngine_x64.exe) For example: Given an excel sheet C:\\myfolder\\sample.xls, with the following data: Name Age Sex Raju 20 Male Ramu 30 Male Sheela 25 Female // Get the DB instance var db = _getDB("sun.jdbc.odbc.JdbcOdbcDriver", "jdbc:odbc:Driver={Microsoft Excel Driver (*.xls, *.xlsx, *.xlsm, *.xlsb)};DBQ=D:\\myfolder\\sample.xls;readOnly=false", "", ""); // Run a select $rs = db.select("select * from [Sheet1$]"); // Assert the first row has Raju in the Name column _assertEqual("Raju", $rs[0]["Name"]); // Assert the first row has 20 in the Age column. // All values will be strings, so we need to parseInt the age. _assertEqual(20, parseInt($rs[0]["Age"])); // Run an update. db.update("update [Sheet1$] set Age=21 where Name='Raju'"); // Do a select again to verify $rs = db.select("select * from [Sheet1$]"); _assertEqual(21, parseInt($rs[0]["Age"])); Note the readOnly=false in the connection string on the first line. This is required if you wish to update the Excel sheet. If you do not add readOnly=false, you will get an error like this: java.sql.SQLException: [Microsoft][ODBC Excel Driver] Operation must use an updateable query.
Sahi Pro
114
Working with files API Notes Syntax _readFile(filePath) Returns the contents of the file as a single String. This is the simplest way of reading a files contents. _readFile( filePath ) filePath: Path of file to read. Paths are relative to the scripts location. Specify absolute path if the file should be read from any other path. var $contents = _readFile("C:/contents.txt"); Here, $contents is a string that contains text from contents.txt readfile.sah _writeFile(text, filePath[, overwrite]) Writes the text into file at filePath. _writeFile( text, filePath[, overwrite] ) text: text to write filePath: Path of file to write to. Paths are relative to the scripts location. Specify absolute path if the file should be created in any other path. overwrite: true if contents of file need to be overwritten. Default: false _writeFile("some text", "C:/info.txt"); The contents of info.txt will be some text. Note: If the file is not available, it is automatically created at the path _writeToFile(text, filePath[, overwrite]) Writes the text into file at filePath. _writeToFile( text, filePath[, overwrite] ) text: text to write filePath: Path of file to write to. Paths are relative to the scripts location. Specify absolute path if the file should be created in any other path. overwrite: true if contents of file need to be overwritten. Default: false _writeToFile("some text", "C:/info.txt"); The contents of info.txt will be some text. Note: If the file is not available, it is automatically created at the path
Example
Example
Sahi Pro
115
_readCSVFile(filePath, wordSeparator) Reads a csv file and returns a 2 dimensional array of the contents. If the separator between words is not a comma, it can be specified as the second parameter. _readCSVFile(filePath, wordSeparator) filePath: Path of the CSV file to read. Paths are relative to the scripts location. Specify absolute path if the file should be read from any other path. wordSeparator: Separator between words. Default: , (comma) var $data = _readCSVFile("simple.csv", "|"); var $row = null ; for (var $i=0; $i<$data.length; $i++){ for (var $j=0; $j<$data[$i].length; $j++){ _click(_link($data[$i][$j])); } } This example reads contents from a | separated CSV file which contains a list of link identifiers. A click action is then performed on each of these links. csv.sah _writeCSVFile(array2d, filePath, overwrite, wordSeparator) Writes a 2 dimensional array into a file in CSV format, using the given wordSeparator (default is comma) _writeCSVFile( array2d, filePath[, overwrite, wordSeparator] ) array2d: 2 dimensional array filePath: Path of the file to write to. Paths are relative to the scripts location. Specify absolute path if the file should be created in any other path. overwrite: if true, overwrites the file. Default: false wordSeparator: Separator between words var $ar = new Array(); $ar[$ar.length] = [ "hi", "there", "one", "a\"b"]; _writeCSVFile($ar, "sahicsv.txt", true); csv.sah _deleteFile(filePath) Deletes the file at filePath. _deleteFile(filePath) filePath: Path of the file to delete. Paths are relative to the scripts location. Specify absolute path if the file should be deleted from any other path. _deleteFile("sahicsv.txt");
Example
Example
Example
Sahi Pro
116
_renameFile(oldFilePath, newFilePath) Renames (or moves) a given file from oldFilePath to newFilePath. If newFilePath already exists, it will be overwritten _renameFile( oldFilePath, newFilePath ) oldFilePath: Path of file to rename / move newFilePath: New path _renameFile("sahicsv.txt", "C:/newSahiCSV.txt");
Example
Data driven testing Sahi has some nice inbuilt features for data-driven testing. The core concept is that data is present as a grid of rows and columns, and tests need to run with each row of the grid as input. Suppose we have a 2-dimensional array of data, on which we perform an add operation: function doAdd($first, $second, $total){ _setValue(_textbox("first"), $first); _setValue(_textbox("second"), $second); _click(_button("Add")); _assertEqual($total, _textbox("total").value); } var $data = [[2, 3, 5], [1, 2, 4], [4, 3, 7]] A simple way to do this is to iterate over the array and invoke the doAdd function with values from each row. for (var $i=0; $i<$data.length; $i++){ var $row = $data[$i]; doAdd($row[0], $row[1], $row[2]); } But, this loop will fail in the second row, since 1+2=3 and not 4, as given in the second row. In case of failure we need to continue to the next row and not stop there. To do this, we use a try catch block. for (var $i=0; $i<$data.length; $i++){ var $row = $data[$i]; try{ doAdd($row[0], $row[1], $row[2]); } catch (e) { // The try catch block helps in continuing with the next // step of data inspite of failures. // _logException so that the logs will indicate the failing line. _logException(e); }} Sahi Pro Tyto Software Pvt. Ltd. 117
All this looping and try catch have been neatly wrapped into a utility function _dataDrive. API Notes Syntax _dataDrive(fn, data2DArray) Loops over data2DArray, and invokes function fn with each row of data. The invocation is within a try catch block with exception logging. _dataDrive(fn, data2DArray) fn: function to call data2DArray: 2 dimensional array to iterate over function doAdd($first, $second, $total){ _setValue(_textbox("first"), $first); _setValue(_textbox("second"), $second); _click(_button("Add")); _assertEqual($total, _textbox("total").value); } var $data = [ [2, 3, 5], [1, 2, 4], [4, 3, 7] ] Note that the function itself is passed to _dataDrive. (No open close brackets after doAdd). Instead of $data being hard coded in the test, you can read it from a CSV file/database or excel sheet. For example, the above code could become function doAdd($first, $second, $total){ _setValue(_textbox("first"), $first); _setValue(_textbox("second"), $second); _click(_button("Add")); _assertEqual($total, _textbox("total").value); } var $data = _readCSVFile("path/to/data_file.csv"); _dataDrive(doAdd, $data); Sahi can read and write to CSV (Comma Separated Value) files, databases and Excel sheets. Other APIs that can be used for data driven testing are: _readCSVFile() _writeCSVFile() _getDB()
Example
Sahi Pro
118
APIs for browser detection API Notes API Notes API Notes API Notes API Notes _isIE(), _isIE9() Returns true if browser is Internet Explorer _isFF(), _isFF2(), _isFF3(), _isFF4(), isFF5() Returns true if browser is Mozilla Firefox _isChrome() Returns true if browser is Google Chrome _isSafari() Returns true if browser is Safari _isOpera() Returns true if browser is Opera
APIs for screen capture There are two APIs that capture the state of the screen for a step during script execution. API Notes Example _takeSnapShot() _takeSnapShots( toggle ) _takeSnapShot() Used to take a snapshot of a single step _click(_link("Click me")); _takeSnapShot(); This will capture the state of the screen when the link Click me is clicked. createSnapShot.sah
Demo Script
Sahi Pro
119
_takeSnapShots(toggle) Used when snapshots are necessary for multiple steps _takeSnapShots(toggle) toggle: set to true to start capturing screenshots. Should be set to false to stop capturing screenshots. _takeSnapShots (true); //Start screen capture _setValue(_password("password"), "secret"); //Screenshot taken _click(_submit("Login")); //Screenshot taken _takeSnapShots (false); //Stop screen capture createSnapShot.sah
Example
Demo Script
Sahi Pro
120
Sahi Pro
121
<target name="start" description="starts proxy"> <java classname="net.sf.sahi.Proxy" fork="true"> <classpath location="lib/sahi.jar"> <pathelement location="extlib/rhino/js.jar"/> <pathelement location="extlib/apc/commons-codec-1.3.jar"/> <pathelement location="extlib/license/truelicense.jar"/> <pathelement location="extlib/license/truexml.jar"/> <pathelement location="extlib/db/h2.jar" /> <fileset dir="extlib" includes="*.jar"/> </classpath> <arg value="." id="basePath"/> <arg value="userdata" id="userdataPath"/> </java> </target> <target name="stopsahi" description="stop sahi server"> <sahi stop="true" sahihost="localhost" sahiport="9999"/> </target> <target name="failsahi" if="sahi.failed"> <fail message="Sahi tests failed!"/> </target> </project>
Let us assume that Jenkins is available in C:\.jenkins\ To run this Ant target from Jenkins, follow these steps. From the Jenkins dashboard, click on "New job". Enter job name as "SahiPro" (This will be the name of the job identified by Jenkins.) Select Build a free-style software project . Click OK. You should see a folder by name "SahiPro" when you navigate to C:\.jenkins\jobs from the file explorer You should then be directed to the Configure page. Click on "Add build step". Select "invoke Ant" Type "-f jenkins-sample.xml ff" In "Post Build Actions", check " Publish JUnit test result report" and add this in the textbox "userdata/temp/junit/reports/*.xml" Click Save. On the left menu, click Build now. This will create a workspace for your project. NOTE: The build will fail, but that is fine. Now, if Sahi Pro is installed in C:\SahiPro, navigate to that folder on your explorer. Copy all the contents inside C:\SahiPro and paste it in "C:\.jenkins\jobs\SahiPro\workspace". Your workspace folder should now look like C:\SahiPro Now, on the Jenkins dashboard, click "Build now". Tyto Software Pvt. Ltd. 122
Sahi Pro
After the tests have run, you will be able to see "Latest Test Result" on the Project home page. Click on it to view your results. You should have all the reports created at this point.
INFO: This target runs a suite file called demo.suite available in SahiPro\userdata\scripts\demo. This uses http://sahi.co.in/demo/ as the start URL. Hence you see that a property called "urlbase" has a value "sahi.co.in". This is the base url. Jenkins tries to look for reports in the workspace root folder. Please look at a target called "report-gen" in jenkins-sample.xml. You can generate the report in any directory. You will have to be familiar with the Ant <junitreport/> task to achieve this. While specifying the target in "Add build step", it is possible to specify the path to ANY Ant build file. Eg. if you say ant -f C:\sahi_pro\demo.xml all, Ant will run the target "all" in demo.xml
You CAN customize a test to run from Jenkins without moving Sahi into the workspace. Familiarity of Jenkins and Ant is necessary to achieve this.
Sahi Pro
123
What is xvfb?
From wikipedia (http://en.wikipedia.org/wiki/Xvfb): Xvfb or X virtual framebuffer is an X11 server that performs all graphical operations in memory, not showing any screen output. From the point of view of the client, it acts exactly like any other server, serving requests and sending events and errors as appropriate. However, no output is shown. This virtual server does not require the computer it is running on to even have a screen or any input device. Only a network layer is necessary.
Installing Xvfb:
For ubuntu, run apt-get install Xvfb For Fedora, run yum install Xvfb For other linux, Download xvfb.tgz from http://ftp.xfree86.org/pub/XFree86/4.6.0/binaries/FreeBSD-4.x/ Let us consider that the downloaded file is at ~/Downloads. cd / tar xvf ~/Downloads/xvfb.tgz cd /usr sudo mkdir X11R6 sudo cp ~/Downloads/xvfb/*.* /usr/X11R6/ chmod +x bin/Xvfb cd bin Create a new file Xvfb and add the script below,
Sahi Pro
124
#!/bin/sh mode=$1 case "$mode" in 'start') if [ -f /usr/X11R6/bin/Xvfb ]; then echo "***Starting up the Virtual Frame Buffer on Screen 1***" /usr/X11R6/bin/Xvfb :1 -screen 0 1152x900x8 & fi ;; *) echo " Usage: " echo " $0 start (start XVFB)" echo " $0 stop (stop XVFB - not supported)" exit 1 ;; esac exit 0
chmod +x Xvfb
or Click on Configure link on Dashboard, and add the above entries before the ending </browserTypes> tag in browser_types.xml Save and restart Sahi. To run a test in Xvfb: navigate to sahi/userdata/bin on terminal and run the command: testrunner.sh demo/sahi_demo.sah http://sahi.co.in/demo/ firefox-xvfb
Sahi Pro
125
var $x = new XML(xmlStr); _assertEqual("Ant", $x.person[0].name.toString()); _assertEqual("Grey", $x.person[1].eyes.toString()); for each (var $p in $x.person){ var $measure = $p.height.@measure.toString(); _assert($measure == "metric"); _assert($p.height > 170); }
Sahi Pro
126
key by which this browserType will be referred Text visible on the Sahi Dashboard png icon. These are bundled inside Sahi path to browser executable. If you run this from a command line, it should invoke the browser options needed by browser. Generally this sets the proxy, and isolates browser sessions so that cookies are not shared. the processName for looking up PID of process. Sahi will do a tasklist or ps with this name to identify the process to kill maximum number of browsers simultaneously executable without overwhelming the system. This depends on your system and you can configure this based on your judgement true/false Specifies if Windows system proxy settings should be changed to use Proxy. Needed by Internet Explorer and Safari on Windows true/false Sahi checks to see that the path attribute above is correct and available on the system. On some OSes the path is not really a file path but a command to invoke the browser. Use force=true in those cases
useSystemProxy force
If your browser is installed in a non standard directory, edit sahi/userdata/browser_types.xml and set the correct path. Alternately, you can click on Configure link on the Sahi Dashboard and edit browser_types.xml. Sahi needs to be restarted for the settings to take effect. Sahi Pro Tyto Software Pvt. Ltd. 127
Sahi comes with default configurations for various browsers and operating systems. These are available in sahi/config/browser_types directory. If sahi/userdata/config/browser_types.xml file is deleted, the correct file will be replaced from the defaults. Default browser configurations for various operating systems: win32.xml win64.xml linux.xml mac.xml
To import the root certificate, click on the SSL link on dashboard. 1. Sahi first tries to import the certificate with certutil command available on Windows. 2. If Step 1 fails, Sahi then tries to import the certificate through Java. At this point you should be able to see this screen
Sahi Pro
128
Click Yes to import the certificate. 3. If Step 2 fails, Sahi will then try a direct import. Follow these steps.
Sahi Pro
129
1 2
5 4
Sahi Pro
130
This should import the certificate successfully. Sahi Pro Tyto Software Pvt. Ltd. 131
My AJAX pages do not render correctly when navigating through Sahi, or I get Javascript errors only when going through Sahi.
Sahi controls the browser by injecting javascript into web pages. However, there are various requests like XMLHttpRequests, javascript, css, etc. where Sahi should not inject its code. While this is correctly detected and handled in most cases, there are instances where one may need to explicitly ask Sahi not to inject code. In such instances, regular expression patterns can be added to exclude_inject.txt. When a URL matches this pattern, Sahi will NOT inject its code. For example while using ExtJS, Add .*callback=.* at the end of sahi/userdata/config/exclude_inject.txt, restart Sahi, clear browser cache, and it should fix problems with AJAX and extjs. You could determine the URL patterns using Firebug on Firefox, or using the Developer Tools on Internet Explorer. If neither of these works for you, enable traffic logging in Sahi and look at the various request responses. To turn on HTTP traffic logging: Click on Enable Traffic Logs on the dashboard. All traffic will be written to userdata/logs/traffic folder organized by date. NOTE: Click on Disable Traffic Logs once you are done, or else the logs will quickly fill your hard disk. To turn on HTTP traffic logging manually: 1. Open sahi/userdata/config/userdata.properties 2. Add (or edit if already present)
debug.traffic.log.unmodified=true debug.traffic.log.modified=true
3. Restart Sahi. NOTE: RESET TRAFFIC LOGGING TO FALSE once you are done, or else the logs will quickly fill your hard disk. Look at response.body_unmodified_xxx and response.body_modified_xxx to see if Sahi has injected code into the file. If yes, add the URL pattern to exclude_inject.txt Note that the pattern needs to be a proper regular expression which will match the whole url. If your url is http://myapp/myajaxrequests.jsp?action=add, your regex may look like .*myajaxrequests[.]jsp.* To explain, . (dot) means any character, *(asterisk) means any number of times, a literal . needs to be escaped by putting in square brackets. So the previous means, any character any number of times, then myajaxrequests, then a literal . (dot), then jsp and again any character any number of times)
Sahi Pro
132
Controller does not identify elements on one website. It works for other websites.
Do a view source on the page and search for document.domain. You may see something like: document.domain = "maindomain.com" This is done by the application developer, so that two frames/iframes from domains like a.maindomain.com and b.maindomain.com can communicate with each other via javascript. To make Sahi work correctly with this, open sahi/userdata/config/domainfix.txt and add *.maindomain.com maindomain.com Save, restart Sahi, and now the Controller should work correctly.
Quick start guide for using PhantomJS with Sahi Pro for load testing:
Download phantomjs-1.x.x-win32-dynamic.zip from http://code.google.com/p/phantomjs/downloads/list Unzip phantomjs-1.x.x-win32-dynamic.zip inside sahi/ext/phantomjs/ folder such that you have sahi/ext/phantomjs/phantomjs.exe
Normal Installation:
1. Download phantomjs-1.x.x-win32-dynamic.zip from http://code.google.com/p/phantomjs/downloads/list 2. Unzip it to, say C:\phantomjs-1.x.x-win32 such that phantomjs.exe is available at C:\phantomjs-1.x.x-win32\phantomjs.exe 3. Create a file sahi.js in C:\phantomjs-1.x.x-win32 with the content below: For version 1.1.0, use:
if (phantom.state.length === 0) { if (phantom.args.length === 0) { console.log('Usage: sahi.js <Sahi Playback Start URL>'); phantom.exit(); } else { var address = unescape(phantom.args[0]); phantom.state = "sahi script running"; console.log('Loading ' + address); phantom.open(address); } } else { if (phantom.loadStatus === 'success') { console.log('Page title is ' + document.title); } else { console.log('FAIL to load the address'); } }
Sahi Pro
134
if (phantom.args.length === 0) { console.log('Usage: sahi.js <Sahi Playback Start URL>'); phantom.exit(); } else { var address = unescape(phantom.args[0]); console.log('Loading ' + address); var page = new WebPage(); page.open(address, function(status) { if (status === 'success') { var title = page.evaluate(function() { return document.title; }); console.log('Page title is ' + title); } else { console.log('FAIL to load the address'); } }); }
The above code is based on the example provided by PhantomJS 4. Click Configure link on Dashboard, and add
<browserType> <name>phantomjs</name> <displayName>PhantomJS</displayName> <icon>safari.png</icon> <path> C:\phantomjs-1.1.0-win32\phantomjs.exe</path> <options>--proxy=localhost:9999 C:\phantomjs-1.1.0-win32\sahi.js</options> <processName>phantomjs.exe</processName> <capacity>100</capacity> <force>true</force> </browserType>
before the ending </browserTypes> tag in browser_types.xml 5. Save and restart Sahi. 6. To run a test in PhantomJS: Click on Bin on the dashboard (or navigate to sahi/userdata/bin on a command prompt) and run the command testrunner.bat demo/sahi_demo.sah http://sahi.co.in/demo/ phantomjs
Sahi Pro
135