18 January 2026:


This forum is now archived and is in read-only mode. Please continue discussions on our improved new Sahi Pro Community forum.



Sahi Pro is an enterprise grade test automation platform which can automate web, mobile, API, windows and java based applications and SAP.

Browser Functions

prutledgeprutledge Members
edited July 2014 in Sahi Pro
Hello, I am hoping that someone can provide super clear instructions on writing custom functions that must run on the browser side (aka pure javascript that uses browser API's like Image, XMLHttpRequest, FileReader, etc.) I have had nothing but inconsistent behavior with them and typically find myself resorting to using something as hideous as (because _call doesn't always work for me?):
_eval("someFunc(" + $args + ")")
and inside of
someFunc
I'm having to set values on the global window object and then retrieve the result later in my Sahi scripts using
_fetch(window.someResultVariable)

I can't make a call directly with
_fetch(someFunc($arg1, $arg2))
like you would expect (and as documented in the API docs?), even though I have defined
<browser> 
    someFunc(arg1, arg2){ return arg1 + arg2; } 
</browser>
.

The only thing I can think of (which makes no sense to me), but is referenced elsewhere in the forums is that it's an issue because I'm importing the <browser> functions from a different file. Regardless, it seems to work inconsistently and significantly hinders my ability to write reliable and maintainable scripts. Can someone either outline a foolproof method of retrieving return values from browser functions that are defined in their own file, or give me any other guidance? Or can we clean up this part of Sahi so it is more reliable?

My suspicions are that whatever is parsing the javascript passed to _call and _fetch (javascript that should be getting run on the browser side since it's calling my browser functions) is failing to parse anything correctly except trivial JS and so by the time it's executed against the browser side it's become inexecutable (maybe a dollar sign issue or something?). Is this due to me not understanding the required JS format when passing to _call and _fetch? My understanding was anything goes (anything that would run fine in a browser console, that is).

Thanks!

Answers

  • prutledgeprutledge Members
    edited August 2014
    To any interested parties, the following module has solved my problems. It is listed below, but also available in this gist: https://gist.github.com/RutledgePaulV/11f477f342da4a8af842

    
    /**
     * This function provides a work around to avoid using these browser tags elsewhere, instead we can call browser side functions
     * straight from a sahi script file and get the appropriate result on the proxy side.
     */
    
    <browser>
    
    function callFunction($name, $args){
    	return window[$name].apply(window, $args);
    }
    
    </browser>
    
    
    /**
     * This utility allows us to ignore using Sahi's <browser> </browser> tags for defining functions that should be run on the browser.
     * Instead we can simply call these utilities to pass functions back and forth between the two, which is super useful.
     */
    var $Browser = (function ($Browser) {
    
    	/**
    	 * Adds a function to the window object on the browser side of things.
    	 *
    	 * @param $key - The name that should be assigned to the function on the browser.
    	 * @param $func - The function that should be used.
    	 */
    	$Browser.addFunction = function ($key, $func) {
    		if (!_condition(window.hasOwnProperty($key))) {
    			_call(window[$key] = $func);
    		} else {
    			_fail("Function already exists on window object.");
    		}
    	};
    
    	/**
    	 * Calls a function on the window object and passes along any provided arguments after the key.
    	 *
    	 * @param $key {string} The name of the function you want to call.
    	 * @param [$args] {...} Any arguments that need to be provided to the function you are calling.
    	 *
    	 * @returns {*} The result of the function you defined, (or nothing if a void function).
    	 */
    	$Browser.callFunction = function ($key, $args) {
    		if (_condition(window.hasOwnProperty($key))) {
    			var $args = [].splice.call(arguments, 1);
    			return _fetch(window.callFunction($key, $args));
    		} else {
    			_fail("Requested function did not exist on the window object.");
    		}
    	};
    
    	/**
    	 * Redefines a function on the window object using the provided key. This is just to avoid developer stupidity.
    	 *
    	 * @param $key {string} The name of the function you want to redefine
    	 * @param $func {Function} The function to be defined for the given key.
    	 */
    	$Browser.redefineFunction = function ($key, $func) {
    		if (_condition(window.hasOwnProperty($key))) {
    			_call(window[$key] = $func);
    		} else {
    			_fail("The function does not yet exist and therefore cannot be redefined.");
    		}
    	};
    
    	/**
    	 * Removes a function definition for a given key on the browser.
    	 *
    	 * @param $key {string} The name of the function to be removed.
    	 */
    	$Browser.removeFunction = function ($key) {
    		if (_condition(window.hasOwnProperty($key))) {
    			_call(window[$key] = undefined);
    		} else {
    			_fail("The function did not exist and so cannot be removed.");
    		}
    	};
    
    	return $Browser;
    })($Browser || {});
    


    Using the above, allows us to do things like the following in a Sahi script:
    $Browser.addFunction("sibling", function (node) {
    	return node.nextElementSibling;
    });
    
    var $results = $Browser.callFunction("sibling",_link({id:"_sahi_ignore_1"}));
    _highlight($results);
    
    
  • One additional note about the above, it should be noted that the browser functions do not persist across page loads when using this method. This can be amended by caching the browser functions on the proxy side and adding them to the browser before each call if they do not exist.
Sign In or Register to comment.