How to add nested functions javascript in custom commands for Nightwatch testing- forEach -loop through elements
Asked 07 September, 2021
Viewed 935 times
  • 51
Votes

Hi I am new to javascript and Nightwatch, I am a manual tester who started doing automation about 6 months ago. I am writing test cases for checking the details of a product, with collapsible menus. Pressing + button will open and display a list of elements, when closing with the same button, it closes the list, and shows a counter with the number of items on the list.

I have a function that is correctly doing this procedure, but I have it written on the test. I would like to use it in the Page where I have all elements and functions related to that page. And I would like to call that function from the test. I have been able to do this, but not with cases with nested functions, because I do not know how to write it.

These are my pages:

   loginPage.js;
   productPage.js;
   productFuntionalityListPage.js;

This is my test:

module.exports = {
    'Buy a Product with Bank Account': function (browser) {
        const login = browser.page.loginPage();
        const productList = browser.page.productPage();
        const productFunctionalityList = browser.page.productFuntionalityListPage();
        


        login
            .navigate()
            .checkLoginPage();

        productList
            .getAProduct()


        //------------------------------------------Features--------------------------------------

        //function to click on each button for functionalities and wait for list to appear
        function displayFunctionsList(elems) {
            elems.value.forEach(function (element) {
                browser.elementIdClick(element.ELEMENT)
                    //wait for list to appear
                    .waitForElementVisible('.list_of_items')
                    .pause(2000)
            })
        }

        // click on each function and wait for list to appear
        browser.elements('css selector', '.expand_collapse_btn', displayFunctionsList, 5000)

        browser.useCss()

        // close each function
        function closeFunctionsList(elems) {
            elems.value.forEach(function (element) {
                browser.elementIdClick(element.ELEMENT)
                    //after click close wait for count to appear
                    .waitForElementVisible("input[data-id='counter']")
                    .pause(2000)
            })
        }

 browser.elements('css selector', '.expand_collapse_btn', closeFunctionsList, 2000)

browser.end()

}
}

This is working correctly.

Below it's what I have tried and does not work:

Page:

productFuntionalityListPage.js

module.exports = {

    elements: {

        counterOfItemsInList: {
            locatorStrategy: 'css selector'
            selector: "input[data-id='counter']",
        },

        expandCollapseBtn: {
            locateStrategy: 'css selector',
            selector: '.expand_collapse_btn',
        },
       listOfItems: {
            locateStrategy: 'css selector',
            selector: '.list_of_items',
        }
  },

commands: [{
        displayFunctionsList: function () {
            function displayFunctionsList(elems) {
                elems.value.forEach(function (element) {
                    this.elementIdClick(element.ELEMENT)
                        //wait for list to appear
                        .waitForElementVisible('@listOfItems')
                        .pause(2000)
                })
            }

            this.elements('css selector', '@expandCollapseBtn', displayFunctionsList, 5000)

        },

 closeFunctionsList: function () {
            function closeFunctionsList(elems) {
                elems.value.forEach(function (element) {
                    this.elementIdClick(element.ELEMENT)
                        //wait for list to appear
                        .waitForElementVisible('@counterOfItemsInList')
                        .pause(2000)
                })
            }

            this.elements('css selector', '@expandCollapseBtn', closeFunctionsList, 5000)

        }


    }]
}

Test calling function from page:

module.exports = {
    'Buy a Product with Bank Account': function (browser) {
        const login = browser.page.loginPage();
        const productList = browser.page.productPage();
        const productFunctionalityList = browser.page.productFuntionalityListPage();
     


        login
            .navigate()
            .checkLoginPage();

        productList
            .getAProduct()


        //------------------------------------------Features--------------------------------------

         //calling displayFunctionsList from productFuntionalityListPage.js
         productFunctionalityList.displayFunctionsList()
         
         //calling closeFunctionsList from productFuntionalityListPage.js
         productFunctionalityList.closeFunctionsList()
         


browser.end()

}
}

Result after running the test above:


Error:
TypeError: this.elements is not a function
   - writing an ES6 async test case? - keep in mind that commands return a Promise; 
   - writing unit tests? - make sure to specify "unit_tests_mode=true" in your config.

Could anyone please help me adding these functions as custom commands in the productFuntionalityListPage.js and call these functions from the test itself? Not sure what's wrong, because of my lack of javascript and nightwatch knowledge.

Thanks a lot for the help!!!!

1 Answer