Forum Discussion

giriprasasd100's avatar
giriprasasd100
Occasional Contributor
14 years ago

How to access 'JScript prototype class methods' from Script Extension

Hi,



I have a script which is written using  JScript inside Script Extension. It is implemented using JScript class, prototype and class methods.



Now I can't access these class methods. The script extension object is loaded and available inside the script units. But while execution of scripts, it prompts error.



Example Script :- (Jscript classes using prototype)



    function Sample()

    {

        //constructor functions

    }



    Sample.prototype.First = function First()

    {

        Log.Message("Method Called");

    }



How to access the prototype methods from extension? Something like Sample.First() ?

JScript Class - Methods, are supported inside Script extension or I am missing any thing here?



Please guide...


4 Replies


  • Hi Giri,





    The scripting engine that executes tests and the engine that is used by the script extension are different. Actually, TestComplete creates something like a wrapper for a script extension based on the Description.xml document. Methods and properties of JScript's custom objects are not passed through this wrapper.





    I have registered your query as a suggestion in our database. Thank you.
  • Do you really need to use Script Extension to accomplish what you are doing? You can create custom classes and prototypes inside the TC jScript engine.



    Since jScript had no equivalent to an Enum, I found this workaround to keep these hard-coded strings limited to a single location in the code base.  (It's a little messy but saves a ton of work and human error.)  This Enum class is located in the same API script unit that it's related function is in so that they are referenced together.



    I apologize for the inclusion of AUT specific code, but I didn't want bother renaming anything to make it generic.  I do have an alternate way to create the same Enum's but it clutters the Code Completion and requires about three times as much code in the class.  I know this isn't directly related to what you are doing, but I'm just saying that it works well inside the TC engine itself.



    /// <summary>

    /// Enum ETabType

    ///

    /// Enum parameters for selecting a Ribbon Tab.

    /// \note Usage: To construct the enum and set the desired value: i.e. SelectTab((new ETabType()).Source())

    /// \note Usage: Evaluate obj._currentState to get current state against available enum values.

    /// </summary>

    /// <returns>A ETabType Enum object</returns>

    function ETabType ()

    {

      this.Source_state = "source"

      this.BeamDisplay_state = "beam display"

      this.Capture_state = "capture"

      this.Computations_state = "computations"

      this.Aperture_state = "aperture"

      this.BeamProfile_state = "beam profile"

      this.Charts_state = "charts"

      this.Logging_state = "logging"

      this.Reports_state = "reports"

      this.ExtraComputations_state = "extracomputations"

    }

    ETabType._currentState = null

    ETabType.prototype.Source = function() {this._currentState = this.Source_state; return this;}

    ETabType.prototype.BeamDisplay = function() {this._currentState = this.BeamDisplay_state; return this;}

    ETabType.prototype.Capture = function() {this._currentState = this.Capture_state; return this;}

    ETabType.prototype.Computations = function() {this._currentState = this.Computations_state; return this;}

    ETabType.prototype.Aperture = function() {this._currentState = this.Aperture_state; return this;}

    ETabType.prototype.BeamProfile = function() {this._currentState = this.BeamProfile_state; return this;}

    ETabType.prototype.Charts = function() {this._currentState = this.Charts_state; return this;}

    ETabType.prototype.Logging = function() {this._currentState = this.Logging_state; return this;}

    ETabType.prototype.Reports = function() {this._currentState = this.Reports_state; return this;}

    ETabType.prototype.ExtraComputations = function() {this._currentState = this.ExtraComputations_state; return this;}


  • giriprasasd100's avatar
    giriprasasd100
    Occasional Contributor
    Thanks David, for registering the problem in database.



    The 'Script Extension' feature is really helpful especially while automating an enterprize level Application where the general fucntionality can be shared across projects suites or literally products. But still this has it own dis-advantages by restrictions like these.



    Russell,



    Already I was using the Jscript class-prototype based script (as Script Unit) in my project suite and now need to share it across different project suites...



    Where (Project Suite / Location) you are storing this ENum class?

    Is it accessible without referencing inside other project suites by default (like Extensions...)



    Please clarify.
  • In my Project Suite I have a "Core" project which houses my testing API that interfaces to my AUT, as well as all of the shared project items (Name Mapping, Events, Stores, etc.).  Then I use other Projects to house tests for several different types of test runs.   The Test projects reference the API Interface units.  What I like to call "Interface Units" allow me to abstract the complexity of normal object mapped TestComplete code away from the test script itself.  this allows anyone on the team to easily understand what the test is doing and what Assertions are being made.  The goal in each test unit is to limit the amount of messy object mapping code and only make calls to the Interface functions.



    Interface units in the Core project must be referenced to any other project that
    needs them which does add a bit of work, but I found that work spent
    developing an API to our AUT was much better than using TC in its more
    simplistic testing approach.



    Suite

       - Core (API project)

          - Script

             - Interfaces

                - IRibbon (Interface Unit)

                   - SelectTab()

                   - ETabType()

       - R1 (test project)

          - Script

             - Interfaces

                - IRibbon (Referenced Interface Unit)

             - Tests

                - SetManualCalibrationValue (Test Unit)

                   - SetManualCalibrationValue()

       - R2 (test project)

          - Script

             - Interfaces

                - IRibbon (Referenced Interface Unit)



    In the sample code I gave you before, the scope of EnumTabType() is limited to when the IRibbon.SelectTab() function is called, so it is in the same unit.   These Classes can be set up in any unit you want to use to pass the Class around, so long as its been referenced in the project, then in the test unit.  The scope works the same as for any other variable you might use.  In my project I use other custom classes and objects in other Interface units in the Core project.  i.e. IVariables - Where I have clusters of variables that are needed throughout the test environment, grouped by uses.



    Here is an example of the end result.  It is very clear what references the script uses, what is being called, and what the test is doing.  It is this same methodology allows custom classes and objects to be passed between each of my different test projects.



    //USEUNIT IAppRunClose

    //USEUNIT IAssert

    //USEUNIT IDataSourceSelect

    //USEUNIT IRibbon

    //USEUNIT ISourceStartStop

    //USEUNIT IComputations_PowerEnergy

    //USEUNIT IDock_Results

    //USEUNIT IUtilities





    function SetManualCalibrationValue()

    {

      var _calValue = 100, _calUnit = 'J', _totalSci = '1.000e+02', _source = 'beammaker';



      IAppRunClose.BGRestart();

      IDataSourceSelect.SelectDataSource(_source);

      ISourceStartStop.SourceStop();

     

      IRibbon.SelectTab(new ETabType().Computations());

      IComputations_PowerEnergy.SetCalibrationValue(_calValue);

      IComputations_PowerEnergy.SetCalibrationUnit(_calUnit);

      IComputations_PowerEnergy.EnableCalibration();

     

      var _total = IDock_Results.getTotalEnergyString();

      var _units = IDock_Results.getTotalEnergyUnits();

     

      IAssert.assert_IsEqual(_total, _totalSci, "Total does not match: \n" +_total+ "\n" +_totalSci);

      IAssert.assert_IsEqual(_units, _calUnit, "Unit does not match: \n" +_units+ "\n" +_calUnit);

     

      _calValue = 200, _calUnit = 'W', _totalSci = '2.000e+02';

        

      IComputations_PowerEnergy.SetCalibrationValue(_calValue);

      IComputations_PowerEnergy.SetCalibrationUnit(_calUnit);

      IComputations_PowerEnergy.EnableCalibration();

      Delay(1000);

     

      _total = IDock_Results.getTotalEnergyString();

      _units = IDock_Results.getTotalEnergyUnits();

     

      IAssert.assert_IsEqual(_total, _totalSci, "Total does not match: \n" +_total+ "\n" +_totalSci);

      IAssert.assert_IsEqual(_units, _calUnit, "Unit does not match: \n" +_units+ "\n" +_calUnit);

     

      IAppRunClose.BGClose();

      IUtilities.LogCount();

    }



    Sorry to drag on but did I give you all the answers you were looking for?  The downside of this approach is how large the project suite gets, where every project has to reference all of the interface units, but it gives me the functionality and robustness that I need.