nightwatch: Element selectors from page sections not working when passed into custom commands

According to @beatfactor ask from #1237 I’m reporting an issue. It looks for me that in v1.0.18 there’s a problem with passing element selectors from page sections into custom commands.

Sample test

I have such Page Object - page:

module.exports = {
    url: function () {
        return this.api.launch_url + '/page/0';
    },

    sections: {

        (...truncated...)

        userMenu: {
            selector : '.usersMenu',
            elements: {
                userName: 'span:first-child',
                userDropdownMenu : '.menu',
                editModeMenuItem : '#editModeMenuItem',
                resetMenuItem : '#resetMenuItem',
                logoutMenuItem: '#logoutMenuItem'
            },
            props: {
                editModeLabel: 'Edit Mode',
                exitModeLabel: 'Exit Edit Mode'
            }
        },

and using such custom command - clickElement:

exports.command = function(selector) {
    return this
        .waitForElementVisible(selector)
        .click(selector, (result) => this.log('Clicked element', result.status === 0 ? 'successfully.' : 'with no success. error - '+result.value.message));
};

from such test file:

var Config = require('../config');

module.exports = {
    'Admin user menu': function (client) {
        client.login()
            .page.page().section.userMenu
            .assert.containsText('@userName', Config.admin)
            .clickElement('@userName')
            .waitForElementVisible('@userDropdownMenu')
            .assert.containsText('#resetMenuItem span','Reset Templates')
            .assert.containsText('#editModeMenuItem span','Edit Mode')
            .assert.containsText('#logoutMenuItem span','Logout');

        client.end();
    },

and it looks like .clickElement('@userName') is called on span:first-child and not on <Section[name=userMenu],Element[name=@userName]> which should be converted to .usersMenu span:first-child. It was working properly (selector was calculated according to section’s selector) in v0.9.21.

Verbose output

→ Running command: containsText ({name, __index, selector, locateStrategy, parent, 'admin')

 → Running command: getText ({name, __index, selector, locateStrategy, parent, [Function])
   Request POST  /wd/hub/session/2faa9b53692e73f5e6e41882027b1560/element  
   { using: 'css selector', value: '.usersMenu' }
   Response 200 POST /wd/hub/session/2faa9b53692e73f5e6e41882027b1560/element (23ms)
   { sessionId: '2faa9b53692e73f5e6e41882027b1560',
     status: 0,
     value: { ELEMENT: '0.1677717170188382-6' } }
   Request POST  /wd/hub/session/2faa9b53692e73f5e6e41882027b1560/element/0.1677717170188382-6/elements  
   { using: 'css selector', value: 'span:first-child' }
   Response 200 POST /wd/hub/session/2faa9b53692e73f5e6e41882027b1560/element/0.1677717170188382-6/elements (28ms)
   { sessionId: '2faa9b53692e73f5e6e41882027b1560',
     status: 0,
     value: [ { ELEMENT: '0.1677717170188382-7' } ] }
   Request GET  /wd/hub/session/2faa9b53692e73f5e6e41882027b1560/element/0.1677717170188382-7/text  
   Response 200 GET /wd/hub/session/2faa9b53692e73f5e6e41882027b1560/element/0.1677717170188382-7/text (25ms)
   { sessionId: '2faa9b53692e73f5e6e41882027b1560',
     status: 0,
     value: 'admin' }
√ Testing if element <Section [name=userMenu],Element [name=@userName]> contains text: "admin"  - 81 ms.
 → Completed command getText ({name, __index, selector, locateStrategy, parent, [Function]) (79ms)
 → Completed command containsText ({name, __index, selector, locateStrategy, parent, 'admin') (84ms)

 → Running command: clickElement ({name, __index, selector, locateStrategy, parent)
   Request POST  /wd/hub/session/2faa9b53692e73f5e6e41882027b1560/element  
   { using: 'css selector', value: '.usersMenu' }
   Response 200 POST /wd/hub/session/2faa9b53692e73f5e6e41882027b1560/element (14ms)
   { sessionId: '2faa9b53692e73f5e6e41882027b1560',
     status: 0,
     value: { ELEMENT: '0.1677717170188382-6' } }
   Request POST  /wd/hub/session/2faa9b53692e73f5e6e41882027b1560/element/0.1677717170188382-6/elements  
   { using: 'css selector', value: 'span:first-child' }
   Response 200 POST /wd/hub/session/2faa9b53692e73f5e6e41882027b1560/element/0.1677717170188382-6/elements (13ms)
   { sessionId: '2faa9b53692e73f5e6e41882027b1560',
     status: 0,
     value: [ { ELEMENT: '0.1677717170188382-7' } ] }

 → Running command: waitForElementVisible ({selector, locateStrategy, name, response)
   Request POST  /wd/hub/session/2faa9b53692e73f5e6e41882027b1560/elements  
   { using: 'css selector', value: 'span:first-child' }
   Response 200 POST /wd/hub/session/2faa9b53692e73f5e6e41882027b1560/elements (20ms)
   { sessionId: '2faa9b53692e73f5e6e41882027b1560',
     status: 0,
     value:
      [ { ELEMENT: '0.1677717170188382-8' },
        { ELEMENT: '0.1677717170188382-9' },
        { ELEMENT: '0.1677717170188382-7' },
        { ELEMENT: '0.1677717170188382-10' },
        { ELEMENT: '0.1677717170188382-11' },
        { ELEMENT: '0.1677717170188382-12' },
        { ELEMENT: '0.1677717170188382-13' },
        { ELEMENT: '0.1677717170188382-14' },
        { ELEMENT: '0.1677717170188382-15' },
        { ELEMENT: '0.1677717170188382-16' },
        { ELEMENT: '0.1677717170188382-17' },
        { ELEMENT: '0.1677717170188382-18' },
        { ELEMENT: '0.1677717170188382-19' },
        { ELEMENT: '0.1677717170188382-20' },
        { ELEMENT: '0.1677717170188382-21' },
        { ELEMENT: '0.1677717170188382-22' },
        { ELEMENT: '0.1677717170188382-23' },
        { ELEMENT: '0.1677717170188382-24' } ] }
  Warning: More than one element (18) found for <span:first-child> with selector: "span:first-child". Only the first one will be used.
   Request GET  /wd/hub/session/2faa9b53692e73f5e6e41882027b1560/element/0.1677717170188382-8/displayed  
   Response 200 GET /wd/hub/session/2faa9b53692e73f5e6e41882027b1560/element/0.1677717170188382-8/displayed (20ms)
   { sessionId: '2faa9b53692e73f5e6e41882027b1560',
     status: 0,
     value: true }
√ Element <span:first-child> was visible after 42 milliseconds.

Configuration

All my work of migrating to new version of nightwatch.js is here: https://github.com/cloudify-cosmo/cloudify-stage/tree/CY-896/e2e

Environment

Nightwatch version: 1.0.18 Node.js version: 8.11.3 OS version: Windows 10 Selenium Server version: selenium-server-standalone-jar v3.12.0 Browser: Google Chrome 71.0.3578.98 (Official Build) (64-bit) & chrome-driver-standalone v2.37.0

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 2
  • Comments: 31 (11 by maintainers)

Most upvoted comments

Unfortunately it is still an issue in version 1.5.1. When you have a section and call a custom command parent selector is omitted and the command is executed in a wrong context.

To simplify the problem I created very simple example showing what is not working fine in >v0.9.21.

`nightwatch.js` - Page Object describing nightwatchjs.org web-page
module.exports = {
    url: 'https://nightwatchjs.org/',

    sections: {
        footerLinks: {
            selector: 'section[id="index-container"] footer div.row div.col-md-2',
            elements: {
                aboutLink: 'li:nth-child(1) a'
            }
        }
    }
};
`clickElement.js` - Custom command
exports.command = function(selector) {
    return this.click(selector);
};
`test.js` - Simple test showing that API works fine, but custom command doing the same is not respecting sections
module.exports = {
    'API command': function(client) {
        const page = client.page.nightwatch();
        const section = page.section.footerLinks;

        page.navigate();
        section.click('@aboutLink');
        client.assert.urlEquals('https://nightwatchjs.org/about/');
    },
    'Custom command': function(client) {
        const page = client.page.nightwatch();
        const section = page.section.footerLinks;

        page.navigate();
        section.clickElement('@aboutLink');
        client.assert.urlEquals('https://nightwatchjs.org/about/');
    }
};

Testing environment:

    "nightwatch": "^1.3.4",
    "chromedriver": "^81.0.0",
    "selenium-server": "^3.141.59",

@beatfactor I would really appreciate if you could take a look on that. We are struggling with NightwatchJS upgrade almost 1,5 year because of that issue.

I digged into NightwatchJS core code, but as I’m not very familiar with it I couldn’t solve it on my own. What I’ve found is that when you pass context as an argument (in my example it can be a section) to custom command and run the API command on that context instead of this it finds the proper element. But I don’t think it should be the solution here.

Is this issue solved?

i get the similar issue when i use nightwatch and selenium-grid

nightwatch version is :v1.2.4 selenium-standalone: selenium-server-standalone-3.141.59.jar from the verbose log, it finds the element, but still get: “not found” error

Response 200 POST http://172.20.10.167:4444/wd/hub/session/17d9ddd6457a620f1ff160a6ff095e24/elements (11ms) { value: [ { ‘element-6066-11e4-a52e-4f735466cecf’: ‘fefbb458-08fc-428d-b82f-99165f1f1904’ } ] } Request POST http://172.20.10.167:4444 /wd/hub/session/17d9ddd6457a620f1ff160a6ff095e24/elements
{ using: ‘css selector’, value: ‘#doxMainLogin’ } Response 200 POST http://172.20.10.167:4444/wd/hub/session/17d9ddd6457a620f1ff160a6ff095e24/elements (9ms) { value: [ { ‘element-6066-11e4-a52e-4f735466cecf’: ‘fefbb458-08fc-428d-b82f-99165f1f1904’ } ] } ✖ Timed out while waiting for element <#doxMainLogin> to be present for 60000 milliseconds. - expected “visible” but got: “not found”

Alright then, we’ll get to the bottom of it.

We will add support for taking into account the global waitForConditionTimeout variable when performing basic commands such as .click() or .getText() so that these commands will wait for the element before performing the action.

As a side note to this particular issue. Maybe implementing a built-in command that would waitAndClick is a good improvement? Seems like many developers are implementing such command.

Can you post it inline please? You can just update your previous comment with the more detailed output.