nightwatchjs / nightwatch

Integrated end-to-end testing framework written in Node.js and using W3C Webdriver API. Developed at @browserstack
https://nightwatchjs.org
MIT License
11.83k stars 1.32k forks source link

moveToElement cannot hover using parsed x, y offsets taken from getElementSize (Nightwatch v2) #3157

Closed chriscuba23 closed 2 years ago

chriscuba23 commented 2 years ago

Describe the bug

Cannot hover using moveToElement with x,y offsets taken from getElementSize anymore. I open my webpage, accept cookies, get the element size of the map, I divide the width and height with 2 so as to calculate the center of the map and hover there. I would expect mouseposition control element of leaflet js library to get updated, but it does not. This works as it should in versions prior to v2

Check the verbose output at the end where the mouseposition control element remains intact:

N00°00'00.00 E000°00'00.00 (00.0000, 000.0000)

if you run against version < 2 then the control element becomes

N25°00'21.50 W018°11'36.09 (25.0060, -018.1934)

which means that the map has been hovered using moveToElement

Sample test

coordinates.js

```js // Please add the sample test here module.exports = { sampleTest: function(browser) { browser .url('https://www.marinetraffic.com') .windowMaximize() //maximize window .waitForElementVisible('div[class*="qc-cmp"] button:nth-child(2)') .click('div[class*="qc-cmp"] button:nth-child(2)') .waitForElementNotPresent('div[class*="qc-cmp"] button:nth-child(2)') .getElementSize('div#map_canvas', function (result) { // get element size and define half width and half height variables var map_x_center = parseInt(result.value.width / 2) var map_y_center = parseInt(result.value.height / 2) console.log(map_x_center, map_y_center) browser .waitForElementVisible('div#map_canvas') .moveToElement('div#map_canvas', map_x_center, map_y_center) // move the mouse to the center of the canvas element (hover over the element) .pause(1000) .getText('div.leaflet-control-mouseposition', (result) => console.log(result.value)) .end() }) } } ```

Run with command

$ nightwatch test/sampleTest.js -e chrome --verbose

Verbose output

debug.log

```txt → Running [beforeEach]: → Completed [beforeEach]. → Running command: url ('https://www.marinetraffic.com') ⠋ Loading url: https://www.marinetraffic.com Request POST /session/cb49b5e2237d4f48e0e676aa9d28fc3e/url ⠧ Loading url: https://www.marinetraffic.com Response 200 POST /session/cb49b5e2237d4f48e0e676aa9d28fc3e/url (673ms) { sessionId: 'cb49b5e2237d4f48e0e676aa9d28fc3e', status: 0, value: null ℹ Loaded url https://www.marinetraffic.com in 687ms → Completed command: url ('https://www.marinetraffic.com') (690ms) → Running command: windowMaximize () Request POST /session/cb49b5e2237d4f48e0e676aa9d28fc3e/window/maximize { windowHandle: 'current' } Response 200 POST /session/cb49b5e2237d4f48e0e676aa9d28fc3e/window/maximize (229ms) { sessionId: 'cb49b5e2237d4f48e0e676aa9d28fc3e', status: 0, value: { height: 1056, width: 1936, x: -8, y: 32 } } → Completed command: windowMaximize () (233ms) → Running command: waitForElementVisible ('div[class*="qc-cmp"] button:nth-child(2)') Request POST /session/cb49b5e2237d4f48e0e676aa9d28fc3e/elements { using: 'css selector', value: 'div[class*="qc-cmp"] button:nth-child(2)' } Response 200 POST /session/cb49b5e2237d4f48e0e676aa9d28fc3e/elements (161ms) { sessionId: 'cb49b5e2237d4f48e0e676aa9d28fc3e', status: 0, value: [] } Request POST /session/cb49b5e2237d4f48e0e676aa9d28fc3e/elements { using: 'css selector', value: 'div[class*="qc-cmp"] button:nth-child(2)' } Response 200 POST /session/cb49b5e2237d4f48e0e676aa9d28fc3e/elements (2220ms) { sessionId: 'cb49b5e2237d4f48e0e676aa9d28fc3e', status: 0, value: [ { ELEMENT: '0.5595098846601925-1' } ] } Request POST /session/cb49b5e2237d4f48e0e676aa9d28fc3e/execute/sync { script: 'return (function(){return (function(){var k=this||self;function aa(a){return"string"==typeof a}function ba(a,b){a=a.split(".");var c=k;a[0]in c||"undefined"==typeof c.execScript||c.execScript("var "+a... (44027 characters)', args: [ { 'element-6066-11e4-a52e-4f735466cecf': '0.5595098846601925-1', ELEMENT: '0.5595098846601925-1' } ] } Response 200 POST /session/cb49b5e2237d4f48e0e676aa9d28fc3e/execute/sync (15ms) { sessionId: 'cb49b5e2237d4f48e0e676aa9d28fc3e', status: 0, value: true } √ Element was visible after 2906 milliseconds. → Completed command: waitForElementVisible ('div[class*="qc-cmp"] button:nth-child(2)') (2910ms) → Running command: click ('div[class*="qc-cmp"] button:nth-child(2)') Request POST /session/cb49b5e2237d4f48e0e676aa9d28fc3e/elements { using: 'css selector', value: 'div[class*="qc-cmp"] button:nth-child(2)' } Response 200 POST /session/cb49b5e2237d4f48e0e676aa9d28fc3e/elements (7ms) { sessionId: 'cb49b5e2237d4f48e0e676aa9d28fc3e', status: 0, value: [ { ELEMENT: '0.5595098846601925-1' } ] } Request POST /session/cb49b5e2237d4f48e0e676aa9d28fc3e/element/0.5595098846601925-1/click {} Response 200 POST /session/cb49b5e2237d4f48e0e676aa9d28fc3e/element/0.5595098846601925-1/click (109ms) { sessionId: 'cb49b5e2237d4f48e0e676aa9d28fc3e', status: 0, value: null } → Completed command: click ('div[class*="qc-cmp"] button:nth-child(2)') (119ms) → Running command: waitForElementNotPresent ('div[class*="qc-cmp"] button:nth-child(2)') Request POST /session/cb49b5e2237d4f48e0e676aa9d28fc3e/elements { using: 'css selector', value: 'div[class*="qc-cmp"] button:nth-child(2)' } Response 200 POST /session/cb49b5e2237d4f48e0e676aa9d28fc3e/elements (24ms) { sessionId: 'cb49b5e2237d4f48e0e676aa9d28fc3e', status: 0, value: [] } √ Element was not present after 25 milliseconds. → Completed command: waitForElementNotPresent ('div[class*="qc-cmp"] button:nth-child(2)') (27ms) → Running command: getElementSize ('div#map_canvas', [Function]) Request POST /session/cb49b5e2237d4f48e0e676aa9d28fc3e/elements { using: 'css selector', value: 'div#map_canvas' } Response 200 POST /session/cb49b5e2237d4f48e0e676aa9d28fc3e/elements (12ms) { sessionId: 'cb49b5e2237d4f48e0e676aa9d28fc3e', status: 0, value: [ { ELEMENT: '0.5595098846601925-2' } ] } Request GET /session/cb49b5e2237d4f48e0e676aa9d28fc3e/element/0.5595098846601925-2/rect Response 200 GET /session/cb49b5e2237d4f48e0e676aa9d28fc3e/element/0.5595098846601925-2/rect (7ms) { sessionId: 'cb49b5e2237d4f48e0e676aa9d28fc3e', status: 0, value: { height: 723, width: 1544, x: 46, y: 48 } } 772 361 → Completed command: getElementSize ('div#map_canvas', [Function]) (24ms) → Running command: waitForElementVisible ('div#map_canvas') Request POST /session/cb49b5e2237d4f48e0e676aa9d28fc3e/elements { using: 'css selector', value: 'div#map_canvas' } Response 200 POST /session/cb49b5e2237d4f48e0e676aa9d28fc3e/elements (7ms) { sessionId: 'cb49b5e2237d4f48e0e676aa9d28fc3e', status: 0, value: [ { ELEMENT: '0.5595098846601925-2' } ] } Request POST /session/cb49b5e2237d4f48e0e676aa9d28fc3e/execute/sync { script: 'return (function(){return (function(){var k=this||self;function aa(a){return"string"==typeof a}function ba(a,b){a=a.split(".");var c=k;a[0]in c||"undefined"==typeof c.execScript||c.execScript("var "+a... (44027 characters)', args: [ { 'element-6066-11e4-a52e-4f735466cecf': '0.5595098846601925-2', ELEMENT: '0.5595098846601925-2' } ] } Response 200 POST /session/cb49b5e2237d4f48e0e676aa9d28fc3e/execute/sync (70ms) { sessionId: 'cb49b5e2237d4f48e0e676aa9d28fc3e', status: 0, value: true } √ Element was visible after 81 milliseconds. → Completed command: waitForElementVisible ('div#map_canvas') (82ms) → Running command: moveToElement ('div#map_canvas', 772, 361) Request POST /session/cb49b5e2237d4f48e0e676aa9d28fc3e/elements { using: 'css selector', value: 'div#map_canvas' } Response 200 POST /session/cb49b5e2237d4f48e0e676aa9d28fc3e/elements (101ms) { sessionId: 'cb49b5e2237d4f48e0e676aa9d28fc3e', status: 0, value: [ { ELEMENT: '0.5595098846601925-2' } ] } Request POST /session/cb49b5e2237d4f48e0e676aa9d28fc3e/actions { actions: [ { actions: [ { type: 'pointerMove', origin: [Object], duration: 100, x: 772, y: 361 } ], parameters: { pointerType: 'mouse' }, type: 'pointer', id: 'default mouse' } ] } Response 200 POST /session/cb49b5e2237d4f48e0e676aa9d28fc3e/actions (131ms) { sessionId: 'cb49b5e2237d4f48e0e676aa9d28fc3e', status: 0, value: null } → Completed command: moveToElement ('div#map_canvas', 772, 361) (237ms) → Running command: pause (1000) → Completed command: pause (1000) (1003ms) → Running command: getText ('div.leaflet-control-mouseposition', [Function]) Request POST /session/cb49b5e2237d4f48e0e676aa9d28fc3e/elements { using: 'css selector', value: 'div.leaflet-control-mouseposition' } Response 200 POST /session/cb49b5e2237d4f48e0e676aa9d28fc3e/elements (12ms) { sessionId: 'cb49b5e2237d4f48e0e676aa9d28fc3e', status: 0, value: [ { ELEMENT: '0.5595098846601925-3' } ] } Request GET /session/cb49b5e2237d4f48e0e676aa9d28fc3e/element/0.5595098846601925-3/text Response 200 GET /session/cb49b5e2237d4f48e0e676aa9d28fc3e/element/0.5595098846601925-3/text (11ms) { sessionId: 'cb49b5e2237d4f48e0e676aa9d28fc3e', status: 0, value: "N00°00'00.00\nE000°00'00.00\n(00.0000, 000.0000)" } N00°00'00.00 E000°00'00.00 (00.0000, 000.0000) → Completed command: getText ('div.leaflet-control-mouseposition', [Function]) (27ms) → Running command: end () → Running command: session ('delete', [Function]) Request DELETE /session/cb49b5e2237d4f48e0e676aa9d28fc3e Response 200 DELETE /session/cb49b5e2237d4f48e0e676aa9d28fc3e (34ms) { sessionId: 'cb49b5e2237d4f48e0e676aa9d28fc3e', status: 0, value: null } → Completed command: end () (41ms) → Completed command: session ('delete', [Function]) (39ms) → Running [afterEach]: → Completed [afterEach]. OK. 3 assertions passed. (5.41s) → Running [after]: → Completed [after]. HTML Report Generated at: reports\chrome_1650307015343.html Wrote report file to: reports\CHROME_100.0.4896.88_Windows_moveTo.xml. ```

Configuration

nightwatch.json

```js { // Autogenerated by Nightwatch // Refer to the online docs for more details: https://nightwatchjs.org/gettingstarted/configuration/ const Services = {}; loadServices(); require('dotenv').config(); const FAILURES_ERRORS_PATH = "./failures"; // Location of the screenshots taken on failures/errors const REPORTS = "./reports"; // The location where the JUnit XML report files will be saved. module.exports = { // An array of folders (excluding subfolders) where your tests are located; // if this is not specified, the test source must be passed as the second argument to the test runner. src_folders: ["Scenarios"], // See https://nightwatchjs.org/guide/working-with-page-objects/ page_objects_path: "pages", // See https://nightwatchjs.org/guide/extending-nightwatch/#writing-custom-commands custom_commands_path: ["./custom_commands", "./node_modules/nightwatch-xhr/es5/commands", "./node_modules/nightwatch-mixpanel/es5/commands", "./node_modules/nightwatch-vrt/commands"], // See https://nightwatchjs.org/guide/extending-nightwatch/#writing-custom-assertions custom_assertions_path: ["./custom_assertions", "./node_modules/nightwatch-xhr/es5/assertions", "./node_modules/nightwatch-mixpanel/es5/assertions", "node_modules/nightwatch-vrt/assertions"], // See https://nightwatchjs.org/guide/#external-globals globals_path: "./globals.js", data_path: "data", output_folder: REPORTS, // The location where the JUnit XML report files will be saved. live_output: false, // Whether or not to buffer the output in case of parallel running detailed_output: true, // By default detailed assertion output is displayed while the test is running. Set this to `false` if you'd like to only see the test case name displayed and pass/fail status. Detailed output is disabled by default when running tests in parallel. //parallel_process_delay: 1000, // Specifies the delay (in milliseconds) between starting the child processes when running in parallel mode. webdriver: { "keep_alive": true // Enable HTTP Keep-Alive. If set to true the keepAlive option is enabled with default settings (keepAliveMsecs = 3000). If set to an object, can specify specify the keepAliveMsecs value. }, // This object contains all the test related options. test_settings: { default: { disable_error_log: false, // Set this to true if you'd like to not display errors during the execution of the test (they are shown at the end always). launch_url: "http://localhost", // A url which can be used later in the tests as the main url to load. Can be useful if your tests will run on different environments, each one with a different url. silent: true, // Whether to show the extended HTTP traffic command logs from the WebDriver or Selenium server. use_xpath: false, // Use xpath as the default locator strategy test_workers: { "enabled": true, "workers": 25 }, // Whether or not to run individual test files in parallel. If set to `true`, runs the tests in parallel and determines the number of workers automatically. If set to an object, can specify specify the number of workers as `"auto"` or a `number`. globals: require('./globals'), // An object which will be made available within the test and can be overwritten per environment screenshots: { enabled: true, path: FAILURES_ERRORS_PATH, on_failure: true }, desiredCapabilities: { // An object which will be passed to the Selenium WebDriver when a new session will be created. You can specify browser name for instance along with other capabilities. browserName: 'chrome', javascriptEnabled: true, acceptSslCerts: true, browserTag: "mttestcr" }, end_session_on_fail: true, // End the session automatically when the test is being terminated, usually after a failed assertion. skip_testcases_on_fail: true, // Skip the remaining testcases (or test steps) from the same test suite (i.e. test file), when one testcase fails. detailed_output: true, // By default detailed assertion output is displayed while the test is running. Set this to `false` if you'd like to only see the test case name displayed and pass/fail status. This is especially useful when running tests in parallel. webdriver: { start_process: true, // When this is enabled, the Webdriver server is run in background in a child process and started/stopped automatically. Nightwatch includes support for managing Chromedriver, Geckodriver (Firefox), Safaridriver, and Selenium Server. Please refer to the Install Webdriver section for details. server_path: (Services.chromedriver ? Services.chromedriver.path : '') // Only useful if start_process is enabled. }, }, firefox: { desiredCapabilities: { browserName: 'firefox', alwaysMatch: { acceptInsecureCerts: true, 'moz:firefoxOptions': { args: [ // '-verbose' '--window-size=1920,925', '--no-sandbox', ] } }, }, browserTag: "mttestff", webdriver: { start_process: true, port: 4444, server_path: (Services.geckodriver ? Services.geckodriver.path : ''), cli_args: [ // very verbose geckodriver logs // '-vv' ] }, }, h_firefox: { desiredCapabilities: { browserName: 'firefox', alwaysMatch: { acceptInsecureCerts: true, 'moz:firefoxOptions': { args: [ '--headless', // '-verbose' '--window-size=1920,925', '--no-sandbox', ] } }, }, browserTag: "mttestff", webdriver: { start_process: true, port: 4444, server_path: (Services.geckodriver ? Services.geckodriver.path : ''), cli_args: [ // very verbose geckodriver logs // '-vv' ] }, }, chrome: { desiredCapabilities: { browserName: 'chrome', loggingPrefs: { browser: "ALL" }, javascriptEnabled: true, acceptSslCerts: true, 'goog:chromeOptions': { // More info on Chromedriver: https://sites.google.com/a/chromium.org/chromedriver/ // // This tells Chromedriver to run using the legacy JSONWire protocol (not required in Chrome 78) w3c: false, args: [ '--no-sandbox', //'--ignore-certificate-errors', //'--allow-insecure-localhost', '--disable-software-rasterizer', '--disable-gpu', '--window-size=1920,925', '--log-level=3', '--disable-logging' ], prefs: { "profile.default_content_setting_values.cookies": 1, // Allow sites to save and read cookie data (recommended): 2=Blocked, 1=Allow }, } }, webdriver: { start_process: true, port: 9515, server_path: (Services.chromedriver ? Services.chromedriver.path : ''), cli_args: [ // --verbose ] }, }, h_chrome: { desiredCapabilities: { browserName: 'chrome', loggingPrefs: { browser: "ALL" }, javascriptEnabled: true, acceptSslCerts: true, 'goog:chromeOptions': { // More info on Chromedriver: https://sites.google.com/a/chromium.org/chromedriver/ // // This tells Chromedriver to run using the legacy JSONWire protocol (not required in Chrome 78) w3c: false, args: [ '--no-sandbox', '--ignore-certificate-errors', '--allow-insecure-localhost', '--headless', '--disable-gpu', '--disable-software-rasterizer', //'--verbose', '--window-size=1920,925', '--log-level=3', '--disable-logging' ], prefs: { "profile.default_content_setting_values.cookies": 1, // Allow sites to save and read cookie data (recommended): 2=Blocked, 1=Allow }, }, }, webdriver: { start_process: true, port: 9515, server_path: (Services.chromedriver ? Services.chromedriver.path : ''), cli_args: [ // --verbose ] }, }, edge: { desiredCapabilities: { browserName: 'MicrosoftEdge', acceptSslCerts: true, 'ms:edgeOptions': { w3c: false, // More info on EdgeDriver: https://docs.microsoft.com/en-us/microsoft-edge/webdriver-chromium/capabilities-edge-options args: [ ] }, browserTag: "mtteste" }, webdriver: { start_process: true, // Download msedgedriver from https://docs.microsoft.com/en-us/microsoft-edge/webdriver-chromium/ // and set the location below: server_path: "C:\\Windows\\System32\\msedgedriver.exe", cli_args: [ // --verbose ] }, }, h_edge: { desiredCapabilities: { browserName: 'MicrosoftEdge', 'ms:edgeOptions': { w3c: false, // More info on EdgeDriver: https://docs.microsoft.com/en-us/microsoft-edge/webdriver-chromium/capabilities-edge-options args: [ '--no-sandbox', //'--ignore-certificate-errors', //'--allow-insecure-localhost', '--headless', '--window-size=1920,925', '--log-level=3', '--disable-gpu', '--disable-software-rasterizer', ] }, browserTag: "mtteste" }, webdriver: { start_process: true, // Download msedgedriver from https://docs.microsoft.com/en-us/microsoft-edge/webdriver-chromium/ // and set the location below: server_path: "C:\\Windows\\System32\\msedgedriver.exe", cli_args: [ // --verbose ] }, }, safari: { test_workers: { "enabled": false }, desiredCapabilities: { acceptInsecureCerts: false, browserName: 'safari', browserTag: "mttests", }, webdriver: { port: 4445, start_process: true, server_path: '/usr/bin/safaridriver' } }, ////////////////////////////////////////////////////////////////////////////////// // Configuration for when using the Selenium service, either locally or remote, | // like Selenium Grid | ////////////////////////////////////////////////////////////////////////////////// selenium_server: { // Selenium Server is running locally and is managed by Nightwatch selenium: { start_process: false, host: '127.0.0.1', port: 4444, launch_url: 'http://localhost', server_path: (Services.seleniumServer ? Services.seleniumServer.path : ''), screenshots: { enabled: true, path: FAILURES_ERRORS_PATH, on_failure: true }, cli_args: { 'webdriver.gecko.driver': (Services.geckodriver ? Services.geckodriver.path : ''), 'webdriver.chrome.driver': (Services.chromedriver ? Services.chromedriver.path : '') } } }, 'selenium.chrome': { extends: 'selenium_server', desiredCapabilities: { browserName: 'chrome', javascriptEnabled: true, acceptSslCerts: true, acceptInsecureCerts: true, chromeOptions: { w3c: false, args: [ '--no-sandbox', '--ignore-certificate-errors', '--allow-insecure-localhost', '--headless', '--disable-gpu', '--disable-software-rasterizer', //'--verbose', '--window-size=1920,925', '--log-level=3', '--disable-logging' ] } }, webdriver: { start_process: false, } }, 'selenium.firefox': { extends: 'selenium_server', desiredCapabilities: { browserName: 'firefox', 'moz:firefoxOptions': { args: [ '-headless', // '-verbose' ] } } } } }; function loadServices() { try { Services.seleniumServer = require('selenium-server'); } catch (err) { } try { Services.chromedriver = require('chromedriver'); } catch (err) { } try { Services.geckodriver = require('geckodriver'); } catch (err) { } } } ```

Your Environment

Executable Version
nightwatch --version 2.1.0
npm --version 6.14.13
yarn --version VERSION
node --version v14.17.1
Browser driver Version
chromedriver 100
OS Version
Windows 10 VERSION
gravityvi commented 2 years ago

@chriscuba23, I think there should be a change in documentation. X and Y offsets are now taken from the center of the element provided. Can you try using .moveToElement('div#map_canvas', 0, 0) instead?

beatfactor commented 2 years ago

can we close this?

chriscuba23 commented 2 years ago

can we close this?

lets keep this until tomorrow please

chriscuba23 commented 2 years ago

closing. Thanx everyone for your help