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

Sending both 'capabilities' and 'desiredCapabilities' results in Geckodriver error (master, v1.0.18) #1978

Closed phsultan closed 5 years ago

phsultan commented 5 years ago

Hello,

When configured to manage a Firefox instance directly, Nightwatch sends both desiredCapabilities and capabilities in the initial POST /session request, and capabilities gets the preference then.

However, it looks malformed according to the spec as it does not contain neither a firstMatch array nor a alwaysMatch property.

In my case, this results in having options not being passed, like acceptInsecureCerts in the example below.

Command

$ ./node_modules/nightwatch/bin/nightwatch --env firefox --verbose
 Starting GeckoDriver on port 4444...
 GeckoDriver up and running on port 4444 with pid: 36422 (1210ms).

[Localhost] Test Suite
======================
   Request POST  /session  
   { capabilities: 
      { browserName: 'firefox',
        acceptSslCerts: true,
        javascriptEnabled: true,
        acceptInsecureCerts: true,
        nativeEvents: true,
        'moz:firefoxOptions': 
         { log: { level: 'trace' },
           args: [ '-headless', '-no-remote' ],
           prefs: 
            { 'browser.cache.disk.enable': false,
              'browser.cache.disk.capacity': 0,
              'browser.cache.disk.smart_size.enabled': false,
              'browser.cache.disk.smart_size.first_run': false,
              'browser.sessionstore.resume_from_crash': false,
              'browser.startup.page': 0,
              'media.navigator.streams.fake': true,
              'media.navigator.permission.disabled': true,
              'device.storage.enabled': false,
              'media.gstreamer.enabled': false,
              'browser.startup.homepage': 'about:blank',
              'browser.startup.firstrunSkipsHomepage': false,
              'extensions.update.enabled': false,
              'app.update.enabled': false,
              'network.http.use-cache': false,
              'browser.shell.checkDefaultBrowser': false } },
        name: 'Localhost' },
     desiredCapabilities: 
      { browserName: 'firefox',
        acceptSslCerts: true,
        platform: 'ANY',
        javascriptEnabled: true,
        acceptInsecureCerts: true,
        nativeEvents: true,
        'moz:firefoxOptions': 
         { log: { level: 'trace' },
           args: [ '-headless', '-no-remote' ],
           prefs: 
            { 'browser.cache.disk.enable': false,
              'browser.cache.disk.capacity': 0,
              'browser.cache.disk.smart_size.enabled': false,
              'browser.cache.disk.smart_size.first_run': false,
              'browser.sessionstore.resume_from_crash': false,
              'browser.startup.page': 0,
              'media.navigator.streams.fake': true,
              'media.navigator.permission.disabled': true,
              'device.storage.enabled': false,
              'media.gstreamer.enabled': false,
              'browser.startup.homepage': 'about:blank',
              'browser.startup.firstrunSkipsHomepage': false,
              'extensions.update.enabled': false,
              'app.update.enabled': false,
              'network.http.use-cache': false,
              'browser.shell.checkDefaultBrowser': false } },
        name: 'Localhost' } }
   Response 200 POST /session (13700ms)
   { value: 
      { sessionId: 'ad120774-e6fd-b342-8633-02051a255d66',
        capabilities: 
         { acceptInsecureCerts: false,
           browserName: 'firefox',
           browserVersion: '64.0',
           'moz:accessibilityChecks': false,
           'moz:geckodriverVersion': '0.23.0',
           'moz:headless': false,
           'moz:processID': 36424,
           'moz:profile': '/var/folders/sy/x5byvjsj5_97lz7t5d_sdc0c0000gn/T/rust_mozprofile.h5BmJh2ZSKxm',
           'moz:shutdownTimeout': 60000,
           'moz:useNonSpecCompliantPointerOrigin': false,
           'moz:webdriverClick': true,
           pageLoadStrategy: 'normal',
           platformName: 'mac',
           platformVersion: '18.2.0',
           rotatable: false,
           setWindowRect: true,
           timeouts: { implicit: 0, pageLoad: 300000, script: 30000 },
           unhandledPromptBehavior: 'dismiss and notify' } } }
 Received session with ID: ad120774-e6fd-b342-8633-02051a255d66

 → Running [before]:
Fetching https://localhost:8443

 → Running command: url ('https://localhost:8443')
   Request POST  /session/ad120774-e6fd-b342-8633-02051a255d66/url  
   { url: 'https://localhost:8443' }
   Response 400 POST /session/ad120774-e6fd-b342-8633-02051a255d66/url (3899ms)
   { value: 
      { error: 'insecure certificate',
        message: '',
        stacktrace: 'WebDriverError@chrome://marionette/content/error.js:178:5\nInsecureCertificateError@chrome://marionette/content/error.js:297:5\nhandleReadyState@chrome://marionette/content/listener.js:270:21\nhandleEvent@chrome://marionette/content/listener.js:243:9\n' } }
 Error while running .navigateTo() protocol action: The SSL certificate running on this host cannot be validated. If you wish to force accepting insecure SSL certificates, set acceptInsecureCerts=true in the desiredCapabilities options.

 → Completed command url ('https://localhost:8443') (3900ms)
 → Completed [before].
...

Configuration file

$ cat nightwatch.json 
{
  "src_folders": [
    "tests"
  ],
  "output_folder": "reports",
  "test_settings": {
    "safari": {
      "desiredCapabilities": {
        "browserName": "safari",
        "javascriptEnabled": true,
        "acceptSslCerts": true
      }
    },
    "chrome": {
      "webdriver": {
        "start_process": true,
        "server_path": "./node_modules/.bin/chromedriver",
        "cli_args": [
          "--verbose"
        ],
        "port": 9515
      },
      "desiredCapabilities": {
        "browserName": "chrome",
        "javascriptEnabled": true,
        "acceptSslCerts": true,
        "nativeEvents": true,
        "chromeOptions": {
          "args": [
            "headless",
            "no-sandbox",
            "allow-file-access-from-files",
            "use-fake-device-for-media-stream",
            "use-fake-ui-for-media-stream",
            "disable-translate",
            "no-process-singleton-dialog",
            "mute-audio"
          ]
        }
      }
    },
    "firefox": {
      "webdriver": {
        "start_process" : true,
        "server_path": "./node_modules/.bin/geckodriver",
        "cli_args": [
          "--log", "debug"
        ],
        "port": 4444
      },
      "desiredCapabilities": {
        "browserName": "firefox",
        "javascriptEnabled": true,
        "acceptInsecureCerts": true,
        "nativeEvents": true,
        "moz:firefoxOptions": {
          "log": {
            "level": "trace"
          },
          "args": [
            "-headless",
            "-no-remote"
          ],
          "prefs": {
            "browser.cache.disk.enable": false,
            "browser.cache.disk.capacity": 0,
            "browser.cache.disk.smart_size.enabled": false,
            "browser.cache.disk.smart_size.first_run": false,
            "browser.sessionstore.resume_from_crash": false,
            "browser.startup.page": 0,
            "media.navigator.streams.fake": true,
            "media.navigator.permission.disabled": true,
            "device.storage.enabled": false,
            "media.gstreamer.enabled": false,
            "browser.startup.homepage": "about:blank",
            "browser.startup.firstrunSkipsHomepage": false,
            "extensions.update.enabled": false,
            "app.update.enabled": false,
            "network.http.use-cache": false,
            "browser.shell.checkDefaultBrowser": false
          }
        }
      }
    }
  }
}

The issue has been introduced with version 1.0.15, and there are multiple ways to fix. This patch fixes capabilities by inserting an alwaysMatch property, that matches with desiredCapabilities (without the acceptSslCerts, javascriptEnabled, name, nativeEvents properties that Geckodriver rejects).

diff --git a/lib/transport/transport.js b/lib/transport/transport.js
index 475c2ba..3cecad8 100644
--- a/lib/transport/transport.js
+++ b/lib/transport/transport.js
@@ -490,7 +490,12 @@ class Transport extends EventEmitter {
     }

     if (!settings.webdriver.use_legacy_jsonwire && !usingSeleniumServer) {
-      settings.capabilities = settings.desiredCapabilities;
+      settings.capabilities = { alwaysMatch: settings.desiredCapabilities };
+
+      delete settings.capabilities.alwaysMatch.acceptSslCerts;
+      delete settings.capabilities.alwaysMatch.javascriptEnabled;
+      delete settings.capabilities.alwaysMatch.name;
+      delete settings.capabilities.alwaysMatch.nativeEvents;
     }
   }

Not sure if sending both capabilities and desiredCapabilities is something that's targetted too, we can also think of removing capabilities completely to fix this, and maybe to build it using firstMatch rather than alwaysMatch. Many options on the table here, if that helps, I can work on a PR.

Thanks!

beatfactor commented 5 years ago

As fas as I am aware, desiredCapabilities is no longer supposed to be sent as part of the session request, according to the W3C spec, but it is still sent due to backwards compatibility reasons and should probably be omitted in the case of standalone Geckodriver usage. However, it is more common I believe for Geckodriver to be used through Selenium still.

The spec that we are trying to follow is the official W3C and that one is not very clear on the usage of firstMatch and alwaysMatch.

stale[bot] commented 5 years ago

This issue has been automatically marked as stale because it has not had any recent activity. If possible, please retry using the latest Nightwatch version and update the issue with any relevant details. If no further activity occurs, it will be closed. Thank you for your contribution.