Search code examples
javascriptwebdriver-io

Grouping / nesting get functions


I am extending (sorry for wrong names coming from other languages, I am new in JS) Page Object, by adding a lot of functions, for example firstLevelFunction1 and firstLevelFunction2. My goal is to group these functions, so that I can access them by dot like this: firstLevelGroup.secondLevelFunction1. I created firstLevelGroup in the same way as firstLevelFunction. Function testLevels is just to verify behavior on different levels, when I call it the output is:

first level function1
first level function2
{ get: [Function: get] }
{ get: [Function: get] }

while I expect:

first level function1
first level function2
second level function1
second level function2

My code:

let Page = require('./../page')
let JsTestingPage = Object.create(Page, {

    firstLevelFunction1: {get: function () { return 'first level function1' }},
    firstLevelFunction2: {get: function () { return 'first level function2' }},

    firstLevelGroup: { get: function () {
        return {
            secondLevelFunction1: {
                get: function () {
                    return 'second level function1'
                }
            },
            secondLevelFunction2: {
                get: function () {
                    return 'second level function2'
                }
            }
        }
    }
    },
    testLevels: {value: function () {
        console.log(this.firstLevelFunction1)
        console.log(this.firstLevelFunction2)
        console.log(this.firstLevelGroup.secondLevelFunction1)
        console.log(this.firstLevelGroup.secondLevelFunction2)
    }}

})
module.exports = JsTestingPage

I also tried other versions, with no success. The one above does not return an error at least.

Please advise me what to do to group functions. Also, feel free to say that it makes no sense to group functions at all :)
BTW, this structure (first level) comes more or less from webdriver.io framework. Grouping functions to second level is my idea to make file more clear and structured.


Solution

  • This happens beacuse you're returning an object initializer, where get becomes an ordinary method name, it doesn't create a getter to the inner objects. To fix this, wrap the returned object within Object.create(null, {...}) (or use a more meaningful prototype, if provided), and you'll get what you're expecting.

    let JsTestingPage = Object.create(null, {
      firstLevelFunction1: {
        get: function() {
          return 'first level function1';
        }
      },
      firstLevelFunction2: {
        get: function() {
          return 'first level function2';
        }
      },
      firstLevelGroup: {
        get: function() {
          return Object.create(null, {
            secondLevelFunction1: {
              get: function() {
                return 'second level function1';
              }
            },
            secondLevelFunction2: {
              get: function() {
                return 'second level function2';
              }
            }
          });
        }
      },
      testLevels: {
        value: function() {
          console.log(this.firstLevelFunction1);
          console.log(this.firstLevelFunction2);
          console.log(this.firstLevelGroup.secondLevelFunction1);
          console.log(this.firstLevelGroup.secondLevelFunction2);
        }
      }
    });
    JsTestingPage.testLevels();

    Or alternatively create the getters inside the object initializers:

    firstLevelGroup: {
        get: function() {
            return {
                get secondLevelFunction1 () {
                    return 'second level function1';
                },
                get secondLevelFunction2 () {
                    return 'second level function2';
                }
            }   
        }
    },