0

I have been trying for the past 3 days without success to get a function i'm using to get the CSS Selector paths of a list of elements fitting a certain selector, to work as a custom command in Nightwatch JS.

What you give to the command:

browser.getUniqueCssSelector('.note');

What the output should be:

['HTML> BODY> SECTION.upper-container > DIV.notes:nth-child(1) > DIV.note:nth-child(1)',
'HTML> BODY> SECTION.upper-container > DIV.notes:nth-child(1) > DIV.note:nth-child(2)',
'HTML> BODY> SECTION.upper-container > DIV.notes:nth-child(2) > DIV.note:nth-child(1)',
'HTML> BODY> SECTION.bottom-container > DIV.inner > DIV.notes:nth-child(1) > DIV.note'
'HTML> BODY> SECTION.bottom-container > DIV.inner > DIV.notes:nth-child(2) > DIV.note']

And so and so.

I have tried lots of different ways to implement it but with no success, I am fairly new to Async/Await so I have not been having alot of luck and haven't been able to relate the examples on the Nightwatch.js guide (https://nightwatchjs.org/guide/extending-nightwatch/#writing-custom-commands) to my issue.

I have written the following using the code segment found in How to generate unique css selector for DOM element? :

// getUniqueCssSelector.js file
exports.command = async function(selector) {
        var browser = this;
     let result = browser.execute(function (selector) {

            const nodes = Array.from(document.querySelectorAll(selector))
            var nodesSelectors = [];

            nodes.forEach(node => {
                nodesSelectors.push(getCssSelectorShort(node));
            });
            return nodesSelectors;

            
            function getCssSelectorShort(el) {
                let path = [], parent;
                while (parent = el.parentNode) {
                let tag = el.tagName, siblings;
                path.unshift(
                    el.id ? `#${el.id}` : (
                    siblings = parent.children,
                    [].filter.call(siblings, sibling => sibling.tagName === tag).length === 1 ? tag :
                    `${tag}:nth-child(${1+[].indexOf.call(siblings, el)})`
                    )
                );
                el = parent;
                };
                return `${path.join(' > ')}`;
            };
            
            

        }, [selector], function(res) {
            console.log('************INSIDE COMMAND RETURN CALLBACK ');
            return res;

        })

        return result;

    }


From there, I want in my test code which calls this custom command, to be able to await it. This command will have to be called on multiple elements so making it a callback function, while would work, would also put my code in an eternal callback stack which would make it look very ugly, very fast.

ideally, I want the code to become something like this:

// nwtest.js file
 let nodeSelectorsList= await browser.getUniqueCssSelectors('.note');
            console.log(nodeSelectorsList); // Would bring me back the entire set I posted above.

nodeSelectorsList.forEach(async (noteElement)=> {
                 let resultSingle = await browser.element('css selector', noteElement);
                 console.log(resultSingle); // Should print the elements returned individually
             })

Unfortunately, I always get undefined as the fruit of my efforts. :/

I have been wrecking my brain over this for several days up to almost a week and tried both Promise and Event implementations, but this one was abit beyond me so I call on the help of SO. Any help would be massively appreciated!.

2
  • browser.execute doesn't return a promise, so it is not necessary to await it. The res in the ************INSIDE COMMAND is it right or no? Commented Aug 3, 2020 at 14:48
  • @ManuelSpigolon Correct, It is a leftover from a promise attempt I did, apologies, I'll edit it out. It does return the correct value inside the function(res) callback. I cannot for the life of me figure out how to get it out of there and back to my main file, however. Commented Aug 3, 2020 at 15:47

1 Answer 1

0

I think you can wrap it as a Promise and then await from the outside,

// getUniqueCssSelector.js file

exports.command = function (selector) {
    var browser = this;
    return new Promise(function (resolve, reject) {

        browser.execute(function (selector) {

            const nodes = Array.from(document.querySelectorAll(selector))
            var nodesSelectors = [];

            nodes.forEach(node => {
                nodesSelectors.push(getCssSelectorShort(node));
            });
            return nodesSelectors;


            function getCssSelectorShort(el) {
                let path = [],
                    parent;
                while (parent = el.parentNode) {
                    let tag = el.tagName,
                        siblings;
                    path.unshift(
                        el.id ? `#${el.id}` : (
                            siblings = parent.children,
                            [].filter.call(siblings, sibling => sibling.tagName === tag).length === 1 ? tag :
                            `${tag}:nth-child(${1+[].indexOf.call(siblings, el)})`
                        )
                    );
                    el = parent;
                };
                return `${path.join(' > ')}`;
            };



        }, [selector], function (res) {
            resolve(res);
        });
    });
}

// nwtest.js file

let nodeSelectorsList = await browser.getUniqueCssSelectors('.note');
console.log(nodeSelectorsList); // Would bring me back the entire set I posted above.

nodeSelectorsList.forEach(async (noteElement) => {
    let resultSingle = await browser.element('css selector', noteElement);
    console.log(resultSingle); // Should print the elements returned individually
})

Sign up to request clarification or add additional context in comments.

2 Comments

var browser = this; should be execute out of the new Promise or it will be undefined
Thanks! unfortunately I already tried it and it did not change anything, it might be something to do with how Nightwatch.js handles the exporting, but even as the resolve sends the correct values I receive an undefined on my file.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.