Forum Discussion

jmathew_1's avatar
jmathew_1
New Contributor
11 years ago

TestComplete IDE not recognizing common JavaScript

I have a request/question for SmartBear/Community. Take a look at the attached image and tell me if anyone knows a workaround for this issue. I'm using a very commonly used JavaScript design pattern. TestComplete IDE does not seem to be able to recognize it. It only seems to be able to read till <ScriptName>.<Obj>. It cannot seem to read anything inside the Obj, this is very annoying considering the fact that managing everything using plain functions and not encapsulating them inside an object can become greusome if at all anyone plans on making the code resuable (read function name clashes).



I was wondering if anyone has come across this issue or knows a better design pattern other than creating new functions and global variables without objects.

  • Hi Jerin, unfortunately you are correct, the Test Complete editor can only read till <ScriptName>.<Obj> and there is no way to configure it so it can.


     


    In terms of patterns, I intially made the mistake of assuming the Test Complete JScript runtime was the same as a Web Browser, therefore I implemented a "Class" structure as I would have for a Browser application, e.g. namespaces and encapsulated Constructors and Modules.


     


    As it turns out, the Test Complete run time is not like a Browser run time at all, from what I can work out, when a Script Unit is run, Test Complete seems to do the following:


     


    1. Parses each Script Unit


    2. Creates a singleton for each Script Unit


    3. Each singleton then runs within its own sandbox, effectively making each Sript Unit a "blackbox" that can only interact via messaging, i.e. there is no overarching global object as you would find in a Browser


     


    Point 3 can prove troublesome in that:


    a. Any prototype augmentation (e.g. adding an indexOf method to Array (yes, the Test Complete JScript engine is that prehistoric)) only applies in the Script Unit it is defined in. In order to use an augmented object, a factory function must be provided by the defining Script Unit which other Script Units can call to get an instance of the augmented object.


    b. Exception handling between Script Units sometimes works, depending on whether an Exception is raised in a Script Unit function or within a User object *sigh*.


     


    I have attached a couple of Script Units that demonstrate this.


     


    I recently gutted the entire Namespace structure and removed every Module bar one from our tests as it become a pain in the butt for others to develop with.


    I still extensively use a similar user object pattern as yours, I just have to bite the bullet and rely on documentation and test developer ability instead of intellisense.


     


    I now have the following basic patterns:


    1. Any code I would normally encapsulate in a Closure based Module that would be considered a Static class in C# is now simply global within a Script Unit. The "blackbox" nature of the Test Complete run time provides enough differentiation between same named members in different Script Units, and as it is in house test code, the lack of privacy really isn't an issue. For the odd occasion where privacy is desired, I just define a simple Closure based Module with the private members and simple accessors that the public Script Unit functions can call.


    2. Closure based Modules for a Singleton that represents an entity.


    3. Instantiable Constructor based User Objects that represent test entities.


     


    Hope this helps,


    Phil

  • Philip_Baird's avatar
    Philip_Baird
    Community Expert

    Hi Jerin, unfortunately you are correct, the Test Complete editor can only read till <ScriptName>.<Obj> and there is no way to configure it so it can.


     


    In terms of patterns, I intially made the mistake of assuming the Test Complete JScript runtime was the same as a Web Browser, therefore I implemented a "Class" structure as I would have for a Browser application, e.g. namespaces and encapsulated Constructors and Modules.


     


    As it turns out, the Test Complete run time is not like a Browser run time at all, from what I can work out, when a Script Unit is run, Test Complete seems to do the following:


     


    1. Parses each Script Unit


    2. Creates a singleton for each Script Unit


    3. Each singleton then runs within its own sandbox, effectively making each Sript Unit a "blackbox" that can only interact via messaging, i.e. there is no overarching global object as you would find in a Browser


     


    Point 3 can prove troublesome in that:


    a. Any prototype augmentation (e.g. adding an indexOf method to Array (yes, the Test Complete JScript engine is that prehistoric)) only applies in the Script Unit it is defined in. In order to use an augmented object, a factory function must be provided by the defining Script Unit which other Script Units can call to get an instance of the augmented object.


    b. Exception handling between Script Units sometimes works, depending on whether an Exception is raised in a Script Unit function or within a User object *sigh*.


     


    I have attached a couple of Script Units that demonstrate this.


     


    I recently gutted the entire Namespace structure and removed every Module bar one from our tests as it become a pain in the butt for others to develop with.


    I still extensively use a similar user object pattern as yours, I just have to bite the bullet and rely on documentation and test developer ability instead of intellisense.


     


    I now have the following basic patterns:


    1. Any code I would normally encapsulate in a Closure based Module that would be considered a Static class in C# is now simply global within a Script Unit. The "blackbox" nature of the Test Complete run time provides enough differentiation between same named members in different Script Units, and as it is in house test code, the lack of privacy really isn't an issue. For the odd occasion where privacy is desired, I just define a simple Closure based Module with the private members and simple accessors that the public Script Unit functions can call.


    2. Closure based Modules for a Singleton that represents an entity.


    3. Instantiable Constructor based User Objects that represent test entities.


     


    Hope this helps,


    Phil

  • Philip_Baird's avatar
    Philip_Baird
    Community Expert
    Appologies, the forum will not allow me to attach any files, here is the code:



    SU1.sj



    Array.prototype.indexOf = function( item )


    {


      for ( var j = 0; j < this.length; j++ )


      {


        if ( ( j in this ) && ( this[ j ] == item) ) return j;


      }


      return -1;


    };


     


    function ArrayFactory( init ) {


      if( arguments.length === 1 ){


        return new Array().concat( arguments[ 0 ] );


      }


      return new Array();


    }


     


    var ExceptionRaiser = function() {


      return {


        throwException: function() {


          throw { name: "Exception" };


        }


      }


    }();


     


    function raiseException() {


      throw { name: "Exception" };


    }


     


    function testArray() {


      var x = [ 1, 2, 3, 4 ]


      Log.Message( x.indexOf( 3 ) );


    }


     


    function testArray2() {


      var x = ArrayFactory( [ 1, 2, 3, 4 ] );


      Log.Message( x.indexOf( 3 ) );


    }


     


    function testException() {


      try {


        exceptionRaiser.throwException();


      } catch( exObj ) {


        Log.Message( "Exception" );


      }


    }


     


    function testException2() {


      try {


        raiseException();


      } catch( exObj ) {


        Log.Message( "Exception" );


      }


    }





     

    SU2.sj


    //USEUNIT SU1


     


    function testArray() {


      var x = [ 1, 2, 3, 4 ]


      Log.Message( x.indexOf( 3 ) );


    }


     


    function testArray2() {


      var x = SU1.ArrayFactory( [ 1, 2, 3, 4 ] );


      Log.Message( x.indexOf( 3 ) );


    }


     


    function testException() {


      try {


        SU1.ExceptionRaiser.throwException();


      } catch( exObj ) {


        Log.Message( "Exception" );


      }


    }


     


    function testException2() {


      try {


        SU1.raiseException();


      } catch( exObj ) {


        Log.Message( "Exception" );


      }


    }

  • TanyaYatskovska's avatar
    TanyaYatskovska
    SmartBear Alumni (Retired)

    Hi Jerin,


     


    I can only add that, in our DB, there is a suggestion to update the script engine used by TestComplete at the moment. I've added your vote to it!


     

  • jmathew_1's avatar
    jmathew_1
    New Contributor
    Hey Phil,



    Thank you for the detailed explanation and sharing details of the methodology you use. This answered so many of my other unasked questions as well, I really appreciate your input on this. SmartBear needs to increase the intellisense capabiliteis in their IDE if they plan on giving us such an older version of JavaScript.



    For what its worth, I'm in the process of writing a framework for our automation testing from ground up and had to abandon 90% use of NameSpacing module. We have C# desktop applications, and the methodology I ended up using was saving property-value pair of process, grid, element, Hwnd etc. and using them with the Find() function to search for objects. I use these returned objects to search for child objects to apply final actions. This has worked for me so far and has helped me remove a huge amount of hard coding.



    Regards,

    Jerin
  • From the screenshot it looks like you have 2 units with a global object called "Obj".



    What are you expecting to happen?
  • jmathew_1's avatar
    jmathew_1
    New Contributor
    Hey Nick,



    Here is what my TestConfig Unit looks like



    // Start TestConfig unit



    Obj = {



      SampleVariable = undefined;



      SampleFunction: function SampleFunction( SampleParameter ) {

          // some code

      }



    }



    // End



    Now if you look at my screenshot with this code in perspective, TestComplete IDE in line 24 and 25 should be able to list function and variables from TestConfig Unit.



    So when I type the following (stop at the dot)



    TestConfig.Obj.



    TestComplete should show me a list of function and variable names from the TestConfig Unit. But it does not. This would be useful when my codebase has hundreds of functions. As of now, I will have to remember each functino or look them up when I need to call them. And once you add more than one developer, this would become even more difficult to manage.



    If you take this code in any other IDE (IntelliJ, Netbeans or Eclipse) and try to write JavaScript/JScript code, this would work and the IDE would be able to list the underlying functions and variables from the TestConfig script. As Phil mentioned earlier, this is due to the fact that JScript Engine TestComplete IDE uses is quiet old and Tanya suggested they have added this concern to their list of upcoming enhancements. I hope this helps.
  • Right, I thought you meant the code wasn't running at all, not that it just wasn't being autocompleted.



    Look on it as an exercise in memory training and using function names and parameters that are easy to remember...