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.

trouble getting getElementsByClassName to work in sahi

handytomhandytom Members
edited November -1 in Sahi - Open Source
Hi

I am using the following function to return an array of elements associated with a certain class.
/*Written by Stuart Colville  from muffinresearch co uk*/

function getElementsByClassName($strClass, $strTag, $objContElm) {
    $strTag = $strTag || "*";
    $objContElm = $objContElm || document;
    var $objColl = $objContElm.getElementsByTagName($strTag);
    if (!$objColl.length &&  $strTag == "*" &&  $objContElm.all){
        $objColl = $objContElm.all;
    }
    var $arr = [];
    var $delim = $strClass.indexOf('|') != -1  ? '|' : ' ';
    var $arrClass = $strClass.split($delim);
        for (var $i = 0; $i < $objColl.length; $i++) {
        var $arrObjClass = $objColl[$i].className.split(' ');
        if ($delim == ' ' && $arrClass.length > $arrObjClass.length){
             continue;
        }
        var $c = 0;
        $comparisonLoop:
        for (var $k = 0; $k < $arrObjClass.length; $k++) {
            for (var $m = 0; $m < $arrClass.length; $m++) {
                if ($arrClass[$m] == $arrObjClass[$k]){
                    $c++;
                }
                if (( $delim == '|' && $c == 1) || ($delim == ' ' && $c == $arrClass.length)) {
                    $arr.push($objColl[$i]);
                    break $comparisonLoop;
                }
            }
        }
    }
    return $arr;
}
I know it works correct because I have tested it outside of Sahi.

I call it like this but it returns a length of 0 instead of 8 as expected. It is basically looking for all TR elements that have a class='data'
var $tr_class = getElementsByClassName('data', 'tr');
var $len= $tr_class.length;
How do I get this to work in Sahi, I always thought that Sahi was just Javascript? But even this does not work as expected
$ted =document.getElementsByTagName('tr');
$tedLen = $ted.length;
Any pointers greatly appreciated as I have been messing around with this problem all day to no avail!!

Thanks
Tom

Comments

  • narayannarayan Administrators
    edited April 2008
    Tom,

    Could you also show how you are using this in your script.
    And if possible could you also post the parsed script?

    Most probably you are not using it inside a _set function.

    try this:
    $len = 0;
    _set($len, getElementsByClassName('data', 'tr').length)
    _debug($len)
    
    and
    $tedLen = 0;
    _set($tedLen,  document.getElementsByTagName('tr').length);
    _debug($tedLen);
    
  • Hi Narayan (the 1 man coder|tester|bug fixer & customer support guru :P)

    I have created a slimmed down version as a demo and here is the parsed version of that demo script
    _sahi.scriptScope = function (){
        _sahi.scriptScope.execute = function(s){eval(s);};
    
    //Your code starts
    
    /*Written by Stuart Colville , from muffinresearch co uk */
    function getElementsByClassName($strClass, $strTag, $objContElm) {
    $strTag = $strTag || '*';
    $objContElm = $objContElm || document;
    var $objColl = $objContElm.getElementsByTagName($strTag);
    if (!$objColl.length &&  $strTag == '*' &&  $objContElm.all){
    $objColl = $objContElm.all;
    }
    var $arr = [];
    var $delim = $strClass.indexOf('|') != -1  ? '|' : ' ';
    var $arrClass = $strClass.split($delim);
    for (var $i = 0; $i < $objColl.length; $i++) {
    var $arrObjClass = $objColl[$i].className.split(' ');
    if ($delim == ' ' && $arrClass.length > $arrObjClass.length){
    continue;
    }
    var $c = 0;
    $comparisonLoop:
    for (var $k = 0; $k < $arrObjClass.length; $k++) {
    for (var $m = 0; $m < $arrClass.length; $m++) {
    if ($arrClass[$m] == $arrObjClass[$k]){
    $c++;
    }
    if (( $delim == '|' && $c == 1) || ($delim == ' ' && $c == $arrClass.length)) {
    $arr.push($objColl[$i]);
    break $comparisonLoop;
    }
    }
    }
    }
    return $arr;
    }
    _sahi.schedule("_sahi._assertNotNull(_sahi._eval(_sahi._textbox(\"srvname\")));", "C:\\sahi\\bin\\..\\scripts\\GAPS_GUI_test\\testtom.sah&n=34");
    _sahi.schedule("_sahi._assertNotNull(_sahi._eval(_sahi._select(\"srvtype\")));", "C:\\sahi\\bin\\..\\scripts\\GAPS_GUI_test\\testtom.sah&n=35");
    _sahi.schedule("_sahi._assertNotNull(_sahi._eval(_sahi._select(\"opid\")));", "C:\\sahi\\bin\\..\\scripts\\GAPS_GUI_test\\testtom.sah&n=36");
    //todo class not working correctly
    _sahi.schedule("_sahi._debug('000000000000000');", "C:\\sahi\\bin\\..\\scripts\\GAPS_GUI_test\\testtom.sah&n=38");
    //$tr_class = _sahi._call(getElementsByClassName('data', 'tr'));
    //$len= $tr_class.length;
    //$len=0;
    //_sahi._debug($len);
    _sahi.schedule("_sahi._debug('111111111111111');", "C:\\sahi\\bin\\..\\scripts\\GAPS_GUI_test\\testtom.sah&n=44");
    $tr_class = [];
    var $sahi_cmdLen = _sahi.cmds.length+1;
    _sahi.schedule("_sahi.handleSet('\\$tr_class' + "+s_v($sahi_cmdLen)+", getElementsByClassName('data', 'tr'));", "C:\\sahi\\bin\\..\\scripts\\GAPS_GUI_test\\testtom.sah&n=46");
    $tr_classTemp = _sahi._getGlobal('$tr_class' + _sahi.cmds.length);
    if ($tr_classTemp) $tr_class = $tr_classTemp;
    $len= $tr_class.length;
    _sahi.schedule("_sahi._debug("+s_v($len)+");", "C:\\sahi\\bin\\..\\scripts\\GAPS_GUI_test\\testtom.sah&n=48");
    _sahi.schedule("_sahi._debug('222222222222222');", "C:\\sahi\\bin\\..\\scripts\\GAPS_GUI_test\\testtom.sah&n=50");
    //$tr_class = new Array();
    //_set($tr_class, getElementsByClassName('data', 'tr'));
    //$len=$tr_class.length;
    //_sahi._debug($len);
    _sahi.schedule("_sahi._debug('333333333333333');", "C:\\sahi\\bin\\..\\scripts\\GAPS_GUI_test\\testtom.sah&n=56");
    //$tagLen = 0;
    //_set($tagLen, document.getElementsByTagName('tr').length);
    //_sahi._debug($tagLen);
    _sahi.schedule("_sahi._debug("+s_v($len)+");", "C:\\sahi\\bin\\..\\scripts\\GAPS_GUI_test\\testtom.sah&n=61");
    for($i=0;$i<$len;$i++)
    {
    _sahi.schedule("_sahi._debug("+s_v($tr_class[$i].className)+");", "C:\\sahi\\bin\\..\\scripts\\GAPS_GUI_test\\testtom.sah&n=64");
    _sahi.schedule("_sahi._assertEqual('none', "+s_v($tr_class[$i].style['display'])+");", "C:\\sahi\\bin\\..\\scripts\\GAPS_GUI_test\\testtom.sah&n=66");
    }
    for($i=1;$i<=4;$i++)
    {
    $id = 'datarow_'+$i;
    _sahi.schedule("_sahi._assertEqual('none', top.document.getElementById("+s_v($id)+").style['display']);", "C:\\sahi\\bin\\..\\scripts\\GAPS_GUI_test\\testtom.sah&n=71");
    }
    
    
    //Your code ends
    
    }
    try{_sahi.scriptScope();}catch(e){_sahi.loadError = e; throw e;}
    
    Within it you can see the 3 different ways I tried to call the function. Each one is separated with something like _debug('000000000000000'). I have them commented out so only one runs at a time.

    Here is the html code that the test is run against
    <!DOCTYPE html PUBLIC '-//W3C//DTD XHTML 1.0 Strict//EN'>
    <html >
    <head><title>testtom</title></head>
    <body>
    <div>
    <form method="post" action="testtom.php">
    <table border='1'>
    <tbody>
    <tr><th colspan="3">Service details</th></tr>
    <tr>
      <td>Name</td>
      <td><input name="srvname" size="24" maxlength="48" value="" type="text" /></td>
      <td></td>
    </tr>
    <tr>
      <td>Type</td>
      <td><select name="srvtype" size="1">
      <option value="">-</option>
      <option value="1">Admin</option>
      <option value="2">Data</option>
    </select>
    </td>
      <td></td>
    </tr>
    <tr>
      <td>Operator</td>
      <td>
            <select name="opid" size="1">
              <option value="">-</option>
              <option value="1">data_op</option>
              <option value="2">Default</option>
            </select>
        </td>
      <td></td>
    </tr>
    <tr style="display: none;" class="data"><th colspan="3" >Data settings</th></tr>
    <tr style="display: none;" class="data">
      <td colspan="4">
       <table>
    <tbody><tr>
        <td><div>data ID</div></td>
        <td><div>Tagged</div></td>
        <td><div>Override priority</div></td>
        <td>&nbsp;</td>
       </tr>
    </tbody></table>
      </td>
    </tr>
    <tr style="display: none;" id="datarow_1"> <td colspan="3">
      <table>
       <tbody><tr>
        <td><input name="data" size="6" maxlength="4" value="" type="text" /></td>
            </tr></tbody>
        </table>
     </td>
    </tr>
    <tr style="display: none;" id="datarow_2"> <td colspan="3">
      <table>
       <tbody><tr>
        <td><input name="data2" size="6" maxlength="4" value="" type="text" /></td>
        <td></td>
            </tr></tbody>
        </table>
     </td>
    </tr>
    <tr style="display: none;" id="datarow_3"> <td colspan="3">
      <table>
       <tbody><tr>
        <td><input name="data3" size="6" maxlength="4" value="" type="text" /></td>
        <td></td>
            </tr></tbody>
        </table>
     </td>
    </tr>
    <tr style="display: none;" id="datarow_4"> <td colspan="3">
      <table>
       <tbody><tr>
        <td><input name="data4" size="6" maxlength="4" value="" type="text" /></td>
            </tr></tbody>
        </table>
     </td>
    </tr>
    <tr style="display: none;" class="data"><th colspan="3" >Quality of service</th></tr>
    <tr style="display: none;" class="data">
      <td>QoS</td>
      <td><input name="qos" size="6" maxlength="1" value="" type="text" /></td>
      <td></td>
    </tr>
    <tr style="display: none;" class="data"><th colspan="3" >Limiting</th></tr>
    <tr style="display: none;" class="data">
      <td>Upper </td>
      <td><input name="up" size="6" maxlength="6" value="" type="text" /></td>
      <td></td>
    </tr>
    <tr style="display: none;" class="data">
      <td>Lower</td>
      <td><input name="dn" size="6" maxlength="6" value="" type="text" />
    </td>
      <td></td>
    </tr>
    </tbody></table>
    </form>
    </div>
    </body>
    </html>
    
    If you need anything else just let me know.
    Thanks
    Tom
  • I have still not succeeded in getting this working correctly. Am I doing something really stupid? Any help really appreciated.

    Cheers
    Tom
  • narayannarayan Administrators
    No Tom, nothing stupid surely.
    Sahi script is javascript, but is parsed and mangled a bit.

    Keep these in mind when using variables:

    1) Sahi does not care about variables being prefixed with $, unless you use it inside a scheduler function. In your code, you could get rid of all $s in getElementsByClassName function.

    2) Use _set only when a variable's value is initialized based on the state of a particular page, and cannot be determined at the writing of the script.
    Eg. For a loop of 10, you could just do
    var $len = 10;
    for ($i=0; $i<$len; $i++){...}
    
    But to get the length of the rows in a table on the 3rd screen and then iterate over them, you would have to do,
    var $len=0;
    _set($len, _table("tableId").rows.length);
    for ($i=0; $i<$len; $i++){...}
    
    3) When assigning a value to a $ variable, (i.e. a variable which is going to be used in a scheduler function), assign only constant values, which will survive a JSON serialization and a round trip to the proxy. That means that DOM elements are not to be assigned to Sahi variables. You could however store an array of ids, or array of indexes.
    So _set($trs, getElementsByClassName("data", "tr")) is wrong.
    But _set($trIds, getIdsArray(getElementsByClassName("data", "tr"))) would be fine.
    _set($en, getElementsByClassName("data", "tr").length) is also fine.

    4) As far as possible, find the dom element using a function invoked from the call to the scheduler function.
    In your case, add a function getSingleElement(class, tag, counter) which can be invoked from say, the _log() function.
    Eg. _log(_getText(getSingleElement("data", "tr", $i)), 'custom2');


    So your script could be changed like this to make it work:
    function getElementsByClassName($strClass, $strTag, $objContElm) {...}
    
    function getSingleElement(class, tag, counter, container){
        return getElementsByClassName(class, tag, container)[counter];
    }
    
    
    $len = 0;
    _set($len, getElementsByClassName("data", "tr").length);
    for (var $i=0; $i<$len; $i++){
        _log(_getText(getSingleElement("data", "tr", $i)), 'custom2');
    }
    
    I am glad you asked this question, because it gave me a reason to clarify my thoughts around this and state it as rules.
  • Well Narayan thanks for all you help with this.

    It was great to be spoon-fed the solution in understandable bites :p

    Cheers
    Tom
  • I have got a problem with the function "getElementsByClassName" (see at first posting):

    This function doesn't work fine in Internet Explorer 6. Only in Firefox it works well. In Internet Explorer doesn't Sahi fill the queue, if this function is used before my testscript is attached, but the script with this function is really parsed by Sahi Controller.

    Do you know, why can't be used in Internet Explorer 6?

    Greetz
  • Has no one got a solution to this problem?

    Greetz
Sign In or Register to comment.