Forum Discussion

Roman_O's avatar
Roman_O
New Contributor
6 years ago
Solved

How to export class methods and properties from one module to another?

 Hello All,

As TestComplete is using JS in ES6, I can use classes to create PageObjects and specify properties and methods in my PageObject class, so it will look like follows:

"use strict";

module.exports =
class PageObjectScreen {
constructor() {
this.property1 = a;
this.property2 = b;
this.property3 = c;
}
method1() {
return this.property1;
}
method2() {
return this.property2;
}
method3() {
return this.property3;
}
}

 

In my test I can create an instance of class and use properties and methods:

 

"use strict";

let PageObjectScreen = reguire('pageObjectScreen');

function testFunction() {

let myPage = new PageObjectScreen();
Log.Event(myPage.method2());

}

When I type myPage. I expect the pop-up list withPageObjectScreen properties and methods, but nothing pops up.

It is quite hard and unreasonable to memorize all properties and methods of all classes so, is there a way to add them in TestComplete intellisence (Auto pop-up)?

 

  • Hi,

     

    Just my own private opinion... :)

     

    > simple IntelliSense

    I'm really doubting that it is that simple, considering that it is for untyped dynamic scripting language.

     

    > PageObject is the common test automation design pattern.

    Pattern is not a dogma but just a tool or approach that should be used when it helps but not tried to be applied to any situation.

     

    > c) and d)

    Note, that once TestComplete finds some object (web element or UI control for desktop), it caches this element and uses for subsequent actions over it. As soon as the container for this object or the object itself is rebuilt (as a result of web page reload or Ajax request with partial DOM change or form/window reopen for desktop), the cached object is invalidated, but the reference to it still exists with the only available .Exists property set to false. This is a handy and logical behavoiur that makes it possible to check whether or not the object still exists without the necessity to handle 'not found' exceptions.

    Thus, there is not that much reason to create classes to keep references to objects: you will not be able to initialize them until they are created and stored references will be invalidated as soon as the object in the tested application is disposed of (even if recreated). So, unless you keep a really good control over this, you will have to check if the stored reference to the object is still valid and if not, make a decision whether this is expected and the object must be searched for again, or this is a problem that must be reported.

    Usually, it is enough to search for the objects that you need at the moment in the same function where you need them or to pass as a parameter.

    The only real convenience from classes is that you can make it more obvious what functions in your code are more or less generic ones and what functions are to do certain specific task.

     

    P.S. Don't get me wrong. I'm not saying that PO must not be used. It is quite possible that you will be able to implement it in a handy and usable way. But not a lot of people here mention that they were using it for TestComplete and personally I participated in a project that was initially created with PO pattern in mind and guys that joined this project really tried to keep this pattern. But extra efforts and inconveniences appeared to be that significant that they moved away from PO to the old good set of separate standalone functions.

     

    P.P.S. Decision is yours, but you are warned... :)

     

3 Replies

  • AlexKaras's avatar
    AlexKaras
    Champion Level 3

    Hi,

     

    a)

    > It is quite hard and unreasonable to memorize all properties and methods of all classes

    Alas, you will have to. There is a request for the feature you are talking about but I am not sure how easy to implement it and when (or whether) it will be implemented.

     

    b)

    > create PageObjects

    This is Selenium way and it is not the best one for TestComplete world.

    First of all: TestComplete already provides you with (a kind of) Page Object (PO) model implemented via NameMapping and Aliasing.

    The major problem with PO (please correct me if I am completely wrong here) is that it works well for the 'static' objects that are present on the page upon its load. But it is not that easy to create stable, fast and easy to understand and maintain PO for the page when you need to constantly wait until some object appears and is populated with data (as a result of several Ajax requests) or may not appear at all.

    TestComplete provides a set of .WaitXXX() and .Find_xxx_Ex() methods that handle such situation pretty well.

     

    And, secondly, classes are not the best thing in TestComplete just because of the problem indicated in your message. :)

     

    • Roman_O's avatar
      Roman_O
      New Contributor

      Thanks for your quick response.

       

      a)

      >There is a request for the feature you are talking about but I am not sure how easy to implement

      That's quite a shame that this really impressive app can't afford simple IntelliSense:(

       

      b)

      >This is Selenium way and it is not the best one for TestComplete world.

      PageObject is not the Selenium way, PageObject is the common test automation design pattern.

       

      c)

      >TestComplete already provides you with (a kind of) Page Object (PO) model implemented via NameMapping and Aliasing.

      In TestComplete I use NameMapping or Aliases to initialize page properties.

      e.g. :

      this.someTextField = new TextField(nameMapping);

       

      d)

      >The major problem with PO (please correct me if I am completely wrong here) is that it works well for the 'static' objects that are present on the page upon its load.

      Not really. It is normal way to use accessors rather than constructor for all (not only dynamic) controls.

      Inside get property method you can .Wait(), .Find(), and then initialize and return required prorerty:

       

      get someTextField () {
      if(! this._someTextField ) {
      let propArr = new Array(prop1Name, prop2Name, prop3Name);
      let valuesArr = new Array(prop1Value,prop2Value,prop3Value);
      let aliase = this._aliase.FindChild(propArr,valuesArr,5);
      this._someTextField  = new TextField (aliase);
      }
      return this._someTextField;
      }

       

      • AlexKaras's avatar
        AlexKaras
        Champion Level 3

        Hi,

         

        Just my own private opinion... :)

         

        > simple IntelliSense

        I'm really doubting that it is that simple, considering that it is for untyped dynamic scripting language.

         

        > PageObject is the common test automation design pattern.

        Pattern is not a dogma but just a tool or approach that should be used when it helps but not tried to be applied to any situation.

         

        > c) and d)

        Note, that once TestComplete finds some object (web element or UI control for desktop), it caches this element and uses for subsequent actions over it. As soon as the container for this object or the object itself is rebuilt (as a result of web page reload or Ajax request with partial DOM change or form/window reopen for desktop), the cached object is invalidated, but the reference to it still exists with the only available .Exists property set to false. This is a handy and logical behavoiur that makes it possible to check whether or not the object still exists without the necessity to handle 'not found' exceptions.

        Thus, there is not that much reason to create classes to keep references to objects: you will not be able to initialize them until they are created and stored references will be invalidated as soon as the object in the tested application is disposed of (even if recreated). So, unless you keep a really good control over this, you will have to check if the stored reference to the object is still valid and if not, make a decision whether this is expected and the object must be searched for again, or this is a problem that must be reported.

        Usually, it is enough to search for the objects that you need at the moment in the same function where you need them or to pass as a parameter.

        The only real convenience from classes is that you can make it more obvious what functions in your code are more or less generic ones and what functions are to do certain specific task.

         

        P.S. Don't get me wrong. I'm not saying that PO must not be used. It is quite possible that you will be able to implement it in a handy and usable way. But not a lot of people here mention that they were using it for TestComplete and personally I participated in a project that was initially created with PO pattern in mind and guys that joined this project really tried to keep this pattern. But extra efforts and inconveniences appeared to be that significant that they moved away from PO to the old good set of separate standalone functions.

         

        P.P.S. Decision is yours, but you are warned... :)