Repository: nightwatchjs/nightwatch (js)

Issue:
Browserstack Session URL contains `undefined`
## Describe the bug
When we run tests in Browserstack cloud, and after the successful test run. Users will get the session URL like this `  https://automate.browserstack.com/builds/undefined/sessions/ff3a33f25464220871e9dcec2b006ae8a0bb71ea`. 

Currently, the above URL contains `undefined`, which must be addressed.

## Steps To Reproduce
1. Using the below sample tests, Run tests with Nightwatch on [Browserstack](https://nightwatchjs.org/guide/quickstarts/create-and-run-a-test-with-cloud-providers.html#running-on-browserstack)
2. Check the URL outputted by Nightwatch CLI

## Sample test
<details><summary>sampleTest.js</summary><p>
<!-- browsers demand the next line be empty -->

```js
describe('Ecosia.org Demo', function() {

  before(browser => browser.navigateTo('https://www.ecosia.org/'));

  it('Demo test ecosia.org', function(browser) {
    browser
      .waitForElementVisible('body')
      .assert.titleContains('Ecosia')
      .assert.visible('input[type=search]')
      .setValue('input[type=search]', 'nightwatch')
      .assert.visible('button[type=submit]')
      .click('button[type=submit]')
      .assert.textContains('.layout__content', 'Nightwatch.js');
  });

  after(browser => browser.end());
});
```
</p></details>

**Run with command**
<!-- Include the command used to run the test, if applicable. -->

```sh
$ nightwatch --env browserstack.chrome --verbose
```

### Verbose output
<details><summary>debug.log</summary><p>
<!-- browsers demand the next line be empty -->

```txt
[Ecosia.org Demo] Test Suite
────────────────────────────────────────────────────────
⠋ Connecting to hub.browserstack.com on port 443...
   Request POST https://hub.browserstack.com/wd/hub/session
   {
     desiredCapabilities: {
       browserName: 'chrome',
       chromeOptions: { w3c: true },
       'bstack:options': {
         userName: '<Redacted>',
         accessKey: '<Redacted>'
       },
       name: 'Ecosia.org Demo',
       'goog:chromeOptions': { w3c: true }
     },
     capabilities: {
       alwaysMatch: {
         browserName: 'chrome',
         'bstack:options': {
           userName: '<Redacted>',
           accessKey: '<Redacted>'
         },
         'goog:chromeOptions': { w3c: true }
       }
     }
⠏ Connecting to hub.browserstack.com on port 443...
   Response 200 POST https://hub.browserstack.com/wd/hub/session (4777ms)
   {
     value: {
       sessionId: 'a0b83309bc3022fa457375c2d561df810f97ec3e',
       capabilities: {
         acceptInsecureCerts: false,
         browserName: 'chrome',
         browserVersion: '103.0.5060.114',
         chrome: {
           chromedriverVersion: '103.0.5060.24 (e47b049c438cd0a74dc95a011fceb27db18cb080-refs/branch-heads/5060@{#232})',
           userDataDir: 'C:\\Windows\\proxy\\scoped_dir2900_2099794750'
         },
         'goog:chromeOptions': { debuggerAddress: 'localhost:6037' },
         networkConnectionEnabled: false,
         pageLoadStrategy: 'normal',
         platformName: 'windows',
         proxy: {},
         setWindowRect: true,
         strictFileInteractability: false,
         timeouts: { implicit: 0, pageLoad: 300000, script: 30000 },
         unhandledPromptBehavior: 'dismiss and notify',
         'webauthn:extension:credBlob': true,
         'webauthn:extension:largeBlob': true,
         'webauthn:virtualAuthenticators': true,
         'webdriver.remote.sessionid': 'a0b83309bc3022fa457375c2d561df810f97ec3e'
       },
       platform: 'WINDOWS'
     }
ℹ Connected to hub.browserstack.com on port 443 (4792ms).
  Using: chrome (103.0.5060.114) on WINDOWS.

 Received session with ID: a0b83309bc3022fa457375c2d561df810f97ec3e

   Request GET https://api.browserstack.com/automate/builds.json
 → Running [before]:

 → Running command: navigateTo ('https://www.ecosia.org/')
   Request POST https://hub.browserstack.com/wd/hub/session/a0b83309bc3022fa457375c2d561df810f97ec3e/url
   { url: 'https://www.ecosia.org/' }
   Response 200 GET https://api.browserstack.com/automate/builds.json (1193ms)
[
  {
    automation_build: {
      name: 'Untitled Build',
      duration: null,
      status: 'running',
      hashed_id: '61846c3675047a802aa2ab60ab148cad551d8b11',
      build_tag: null
    }
  }
]
   Response 200 POST https://hub.browserstack.com/wd/hub/session/a0b83309bc3022fa457375c2d561df810f97ec3e/url (2917ms)
   { value: null }
  → Completed command: navigateTo ('https://www.ecosia.org/') (2920ms)
 → Completed [before].



  Running Demo test ecosia.org:
─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────
 → Running [beforeEach]:
 → Completed [beforeEach].

 → Running command: waitForElementVisible ('body')
   Request POST https://hub.browserstack.com/wd/hub/session/a0b83309bc3022fa457375c2d561df810f97ec3e/elements
   { using: 'css selector', value: 'body' }
   Response 200 POST https://hub.browserstack.com/wd/hub/session/a0b83309bc3022fa457375c2d561df810f97ec3e/elements (422ms)
   {
     value: [
       {
         'element-6066-11e4-a52e-4f735466cecf': 'bd14cbd2-1da7-49c7-b208-72a924baeb28'
       }
     ]
  }
   Request POST https://hub.browserstack.com/wd/hub/session/a0b83309bc3022fa457375c2d561df810f97ec3e/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': 'bd14cbd2-1da7-49c7-b208-72a924baeb28',
         ELEMENT: 'bd14cbd2-1da7-49c7-b208-72a924baeb28'
       }
     ]
  }
   Response 200 POST https://hub.browserstack.com/wd/hub/session/a0b83309bc3022fa457375c2d561df810f97ec3e/execute/sync (2092ms)
   { value: true }
  ✔ Element <body> was visible after 2523 milliseconds.
  → Completed command: waitForElementVisible ('body') (2529ms)

 → Running command: assert.titleContains ('Ecosia')

 → Running command: title ([Function])
   Request GET https://hub.browserstack.com/wd/hub/session/a0b83309bc3022fa457375c2d561df810f97ec3e/title

   Response 200 GET https://hub.browserstack.com/wd/hub/session/a0b83309bc3022fa457375c2d561df810f97ec3e/title (276ms)
   { value: 'Ecosia - the search engine that plants trees' }
  ✔ Testing if the page title contains 'Ecosia' (280ms)
  → Completed command: assert.titleContains ('Ecosia') (282ms)
  → Completed command: title ([Function]) (279ms)

 → Running command: assert.visible ('input[type=search]')

 → Running command: isVisible ({selector, suppressNotFoundErrors}, [Function])
   Request POST https://hub.browserstack.com/wd/hub/session/a0b83309bc3022fa457375c2d561df810f97ec3e/elements
   { using: 'css selector', value: 'input[type=search]' }
   Response 200 POST https://hub.browserstack.com/wd/hub/session/a0b83309bc3022fa457375c2d561df810f97ec3e/elements (343ms)
   {
     value: [
       {
         'element-6066-11e4-a52e-4f735466cecf': 'ae3ea7f9-8c13-439e-9800-67cb3f1f6621'
       }
     ]
  }
   Request POST https://hub.browserstack.com/wd/hub/session/a0b83309bc3022fa457375c2d561df810f97ec3e/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': 'ae3ea7f9-8c13-439e-9800-67cb3f1f6621',
         ELEMENT: 'ae3ea7f9-8c13-439e-9800-67cb3f1f6621'
       }
     ]
  }
   Response 200 POST https://hub.browserstack.com/wd/hub/session/a0b83309bc3022fa457375c2d561df810f97ec3e/execute/sync (3411ms)
   { value: true }
  ✔ Testing if element <input[type=search]> is visible (3760ms)
  → Completed command: assert.visible ('input[type=search]') (3761ms)
  → Completed command: isVisible ({selector, suppressNotFoundErrors}, [Function]) (3759ms)

 → Running command: setValue ('input[type=search]', 'nightwatch')
   Request POST https://hub.browserstack.com/wd/hub/session/a0b83309bc3022fa457375c2d561df810f97ec3e/elements
   { using: 'css selector', value: 'input[type=search]' }
   Response 200 POST https://hub.browserstack.com/wd/hub/session/a0b83309bc3022fa457375c2d561df810f97ec3e/elements (635ms)
   {
     value: [
       {
         'element-6066-11e4-a52e-4f735466cecf': 'ae3ea7f9-8c13-439e-9800-67cb3f1f6621'
       }
     ]
  }
   Request POST https://hub.browserstack.com/wd/hub/session/a0b83309bc3022fa457375c2d561df810f97ec3e/element/ae3ea7f9-8c13-439e-9800-67cb3f1f6621/clear
{}
   Response 200 POST https://hub.browserstack.com/wd/hub/session/a0b83309bc3022fa457375c2d561df810f97ec3e/element/ae3ea7f9-8c13-439e-9800-67cb3f1f6621/clear (320ms)
   { value: null }
   Request POST https://hub.browserstack.com/wd/hub/session/a0b83309bc3022fa457375c2d561df810f97ec3e/element/ae3ea7f9-8c13-439e-9800-67cb3f1f6621/value
   {
     text: 'nightwatch',
     value: [
       'n', 'i', 'g', 'h',
       't', 'w', 'a', 't',
       'c', 'h'
     ]
  }
   Response 200 POST https://hub.browserstack.com/wd/hub/session/a0b83309bc3022fa457375c2d561df810f97ec3e/element/ae3ea7f9-8c13-439e-9800-67cb3f1f6621/value (1139ms)
   { value: null }
  → Completed command: setValue ('input[type=search]', 'nightwatch') (2099ms)

 → Running command: assert.visible ('button[type=submit]')

 → Running command: isVisible ({selector, suppressNotFoundErrors}, [Function])
   Request POST https://hub.browserstack.com/wd/hub/session/a0b83309bc3022fa457375c2d561df810f97ec3e/elements
   { using: 'css selector', value: 'button[type=submit]' }
   Response 200 POST https://hub.browserstack.com/wd/hub/session/a0b83309bc3022fa457375c2d561df810f97ec3e/elements (2305ms)
   {
     value: [
       {
         'element-6066-11e4-a52e-4f735466cecf': '004464a7-6497-4a6e-a601-19556818a113'
       }
     ]
  }
   Request POST https://hub.browserstack.com/wd/hub/session/a0b83309bc3022fa457375c2d561df810f97ec3e/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': '004464a7-6497-4a6e-a601-19556818a113',
         ELEMENT: '004464a7-6497-4a6e-a601-19556818a113'
       }
     ]
  }
   Response 200 POST https://hub.browserstack.com/wd/hub/session/a0b83309bc3022fa457375c2d561df810f97ec3e/execute/sync (542ms)
   { value: true }
  ✔ Testing if element <button[type=submit]> is visible (2853ms)
  → Completed command: assert.visible ('button[type=submit]') (2854ms)
  → Completed command: isVisible ({selector, suppressNotFoundErrors}, [Function]) (2852ms)

 → Running command: click ('button[type=submit]')
   Request POST https://hub.browserstack.com/wd/hub/session/a0b83309bc3022fa457375c2d561df810f97ec3e/elements
   { using: 'css selector', value: 'button[type=submit]' }
   Response 200 POST https://hub.browserstack.com/wd/hub/session/a0b83309bc3022fa457375c2d561df810f97ec3e/elements (600ms)
   {
     value: [
       {
         'element-6066-11e4-a52e-4f735466cecf': '004464a7-6497-4a6e-a601-19556818a113'
       }
     ]
  }
   Request POST https://hub.browserstack.com/wd/hub/session/a0b83309bc3022fa457375c2d561df810f97ec3e/element/004464a7-6497-4a6e-a601-19556818a113/click
{}
   Response 200 POST https://hub.browserstack.com/wd/hub/session/a0b83309bc3022fa457375c2d561df810f97ec3e/element/004464a7-6497-4a6e-a601-19556818a113/click (2886ms)
   { value: null }
  → Completed command: click ('button[type=submit]') (3489ms)

 → Running command: assert.textContains ('.layout__content', 'Nightwatch.js')

 → Running command: getText ({selector, suppressNotFoundErrors}, [Function])
   Request POST https://hub.browserstack.com/wd/hub/session/a0b83309bc3022fa457375c2d561df810f97ec3e/elements
   { using: 'css selector', value: '.layout__content' }
   Response 200 POST https://hub.browserstack.com/wd/hub/session/a0b83309bc3022fa457375c2d561df810f97ec3e/elements (285ms)
   {
     value: [
       {
         'element-6066-11e4-a52e-4f735466cecf': 'f041ef16-16b9-4b22-bef1-e013a2f5bda5'
       }
     ]
  }
   Request GET https://hub.browserstack.com/wd/hub/session/a0b83309bc3022fa457375c2d561df810f97ec3e/element/f041ef16-16b9-4b22-bef1-e013a2f5bda5/text

   Response 200 GET https://hub.browserstack.com/wd/hub/session/a0b83309bc3022fa457375c2d561df810f97ec3e/element/f041ef16-16b9-4b22-bef1-e013a2f5bda5/text (517ms)
   {
     value: 'Search\n' +
       'Ad\n' +
       'jobrapido.com › jobs nightwatch\n' +
       'Jobs Nightwatch\n' +
       '5 urgent open positions. Apply now! Jobs N...',
     suppressBase64Data: true
  }
  ✔ Testing if element <.layout__content> contains text 'Nightwatch.js' (809ms)
  → Completed command: assert.textContains ('.layout__content', 'Nightwatch.js') (811ms)
  → Completed command: getText ({selector, suppressNotFoundErrors}, [Function]) (809ms)
 → Running [afterEach]:
 → Completed [afterEach].

OK. 5 assertions passed. (15.83s)
 → Running [after]:

 → Running command: end ()

 → Running command: session ('delete', [Function])
   Request DELETE https://hub.browserstack.com/wd/hub/session/a0b83309bc3022fa457375c2d561df810f97ec3e

   Response 200 DELETE https://hub.browserstack.com/wd/hub/session/a0b83309bc3022fa457375c2d561df810f97ec3e (1435ms)
   { state: 'success', status: 0, value: '' }
  → Completed command: end () (1440ms)
  → Completed command: session ('delete', [Function]) (1439ms)
 → Completed [after].
   Request PUT https://api.browserstack.com/automate/sessions/a0b83309bc3022fa457375c2d561df810f97ec3e.json
   { status: 'passed', reason: '' }
   Response 200 PUT https://api.browserstack.com/automate/sessions/a0b83309bc3022fa457375c2d561df810f97ec3e.json (1327ms)
   {
     automation_session: {
       hashed_id: 'a0b83309bc3022fa457375c2d561df810f97ec3e',
       name: 'Ecosia.org Demo',
       status: 'passed',
       os: 'Windows',
       os_version: '8.1',
       browser: 'chrome',
       browser_version: '103.0',
       device: null,
       duration: 23,
       reason: 'CLIENT_STOPPED_SESSION',
       build_name: 'Untitled Build',
       project_name: 'Untitled Project',
       build_hashed_id: '61846c3675047a802aa2ab60ab148cad551d8b11',
       test_priority: null
     }
  }

  See more info, video, & screenshots on Browserstack:
  https://automate.browserstack.com/builds/undefined/sessions/a0b83309bc3022fa457375c2d561df810f97ec3e
 Wrote JSON report file to: /Users/vaibhavsingh/Dev/nightwatch/tests_output/CHROME_103.0.5060.114__ecosia.json
 Wrote XML report file to: /Users/vaibhavsingh/Dev/nightwatch/tests_output/CHROME_103.0.5060.114__ecosia.xml
Wrote HTML report file to: /Users/vaibhavsingh/Dev/nightwatch/tests_output/nightwatch-html-report/index.html
```
</p></details>


## Configuration
<details><summary>nightwatch.json</summary><p>
<!-- browsers demand the next line be empty -->

<!-- Please paste your nightwatch.json or nightwatch.conf.js here; make sure to leave out any sensitive details -->

```js
// Autogenerated by Nightwatch
// Refer to the online docs for more details: https://nightwatchjs.org/gettingstarted/configuration/
const Services = {}; loadServices();

//  _   _  _         _      _                     _          _
// | \ | |(_)       | |    | |                   | |        | |
// |  \| | _   __ _ | |__  | |_ __      __  __ _ | |_   ___ | |__
// | . ` || | / _` || '_ \ | __|\ \ /\ / / / _` || __| / __|| '_ \
// | |\  || || (_| || | | || |_  \ V  V / | (_| || |_ | (__ | | | |
// \_| \_/|_| \__, ||_| |_| \__|  \_/\_/   \__,_| \__| \___||_| |_|
//             __/ |
//            |___/

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: ['dist/src'],

  // See https://nightwatchjs.org/guide/working-with-page-objects/
  page_objects_path: ['dist/pages'],

  // See https://nightwatchjs.org/guide/extending-nightwatch/#writing-custom-commands
  custom_commands_path: [],

  // See https://nightwatchjs.org/guide/extending-nightwatch/#writing-custom-assertions
  custom_assertions_path: '',

  // See https://nightwatchjs.org/guide/#external-globals
  globals_path: '',

  webdriver: {},

  test_settings: {
    default: {
      disable_error_log: false,
      launch_url: 'https://the-internet.herokuapp.com',

      screenshots: {
        enabled: false,
        path: 'screens',
        on_failure: true
      },

      desiredCapabilities: {
        browserName: 'firefox'
      },

      webdriver: {
        start_process: true,
        server_path: ''
      }
    },

    safari: {
      desiredCapabilities: {
        browserName: 'safari',
        alwaysMatch: {
          acceptInsecureCerts: false
        }
      },
      webdriver: {
        start_process: true,
        server_path: ''
      }
    },

    firefox: {
      desiredCapabilities: {
        browserName: 'firefox',
        alwaysMatch: {
          acceptInsecureCerts: true,
          'moz:firefoxOptions': {
            args: [
              // '-headless',
              // '-verbose'
            ]
          }
        }
      },
      webdriver: {
        start_process: true,
        server_path: '',
        cli_args: [
          // very verbose geckodriver logs
          // '-vv'
        ]
      }
    },

    chrome: {
      desiredCapabilities: {
        browserName: 'chrome',
        'goog:chromeOptions': {
          // More info on Chromedriver: https://sites.google.com/a/chromium.org/chromedriver/
          //
          // w3c:false tells Chromedriver to run using the legacy JSONWire protocol (not required in Chrome 78)
          w3c: true,
          args: [
            //'--no-sandbox',
            //'--ignore-certificate-errors',
            //'--allow-insecure-localhost',
            //'--headless'
          ]
        }
      },

      webdriver: {
        start_process: true,
        server_path: '',
        cli_args: [
          // --verbose
        ]
      }
    },

    edge: {
      desiredCapabilities: {
        browserName: 'MicrosoftEdge',
        'ms:edgeOptions': {
          w3c: true,
          // More info on EdgeDriver: https://docs.microsoft.com/en-us/microsoft-edge/webdriver-chromium/capabilities-edge-options
          args: [
            //'--headless'
          ]
        }
      },

      webdriver: {
        start_process: true,
        // Download msedgedriver from https://docs.microsoft.com/en-us/microsoft-edge/webdriver-chromium/
        //  and set the location below:
        server_path: '',
        cli_args: [
          // --verbose
        ]
      }
    },

    //////////////////////////////////////////////////////////////////////////////////
    // Configuration for when using cucumber-js (https://cucumber.io)                |
    //                                                                               |
    // It uses the bundled examples inside the nightwatch examples folder; feel free |
    // to adapt this to your own project needs                                       |
    //////////////////////////////////////////////////////////////////////////////////
    'cucumber-js': {
      src_folders: ['examples/cucumber-js/features/step_definitions'],

      test_runner: {
        // set cucumber as the runner
        type: 'cucumber',

        // define cucumber specific options
        options: {
          //set the feature path
          feature_path: 'node_modules/nightwatch/examples/cucumber-js/*/*.feature'

          // start the webdriver session automatically (enabled by default)
          // auto_start_session: true

          // use parallel execution in Cucumber
          // parallel: 2 // set number of workers to use (can also be defined in the cli as --parallel 2
        }
      }
    },

    //////////////////////////////////////////////////////////////////////////////////
    // Configuration for when using the browserstack.com cloud service               |
    //                                                                               |
    // Please set the username and access key by setting the environment variables:  |
    // - BROWSERSTACK_USER                                                           |
    // - BROWSERSTACK_KEY                                                            |
    // .env files are supported                                                      |
    //////////////////////////////////////////////////////////////////////////////////
    browserstack: {
      selenium: {
        host: 'hub-cloud.browserstack.com',
        port: 443
      },
      // More info on configuring capabilities can be found on:
      // https://www.browserstack.com/automate/capabilities?tag=selenium-4
      desiredCapabilities: {
        'bstack:options': {
          userName: '${BROWSERSTACK_USER}',
          accessKey: '${BROWSERSTACK_KEY}'
        }
      },

      disable_error_log: true,
      webdriver: {
        timeout_options: {
          timeout: 15000,
          retry_attempts: 3
        },
        keep_alive: true,
        start_process: false
      }
    },

    'browserstack.local': {
      extends: 'browserstack',
      desiredCapabilities: {
        'browserstack.local': true
      }
    },

    'browserstack.chrome': {
      extends: 'browserstack',
      desiredCapabilities: {
        browserName: 'chrome',
        chromeOptions: {
          w3c: true,
          'args': ['start-maximized']
        }
      }
    },

    'browserstack.firefox': {
      extends: 'browserstack',
      desiredCapabilities: {
        browserName: 'firefox'
      }
    },

    'browserstack.ie': {
      extends: 'browserstack',
      desiredCapabilities: {
        browserName: 'internet explorer',
        browserVersion: '11.0'
      }
    },

    'browserstack.safari': {
      extends: 'browserstack',
      desiredCapabilities: {
        browserName: 'safari'
      }
    },

    'browserstack.local_chrome': {
      extends: 'browserstack.local',
      desiredCapabilities: {
        browserName: 'chrome'
      }
    },

    'browserstack.local_firefox': {
      extends: 'browserstack.local',
      desiredCapabilities: {
        browserName: 'firefox'
      }
    },
    //////////////////////////////////////////////////////////////////////////////////
    // 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: true,
        port: 4444,
        server_path: (Services.seleniumServer ? Services.seleniumServer.path : ''),
        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',
        chromeOptions: {
          w3c: true
        }
      }
    },

    '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) {}
}

```
</p></details>

## Your Environment
<!--- Include the relevant details your environment -->

| Executable | Version |
| ---: | :--- |
| `nightwatch --version` | 2.3.0 |
| `npm --version`  | 8.11.0 |
| `node --version` | v16.16.0 |


| OS | Version |
| --- | --- |
| NAME | VERSION |
<!-- For example:
| macOS Monterey | 12.5 |
-->

## Ref
![image](https://user-images.githubusercontent.com/8705386/181044997-79e3d66d-9da7-4892-a47c-686a4d648953.png)


Pull request description:
Added buildname to settings when running on browserstack cloud
fixes #3304 


Patch:
diff --git a/lib/api/_loaders/assertion-scheduler.js b/lib/api/_loaders/assertion-scheduler.js
index fccd331f..0a367c4e 100644
--- a/lib/api/_loaders/assertion-scheduler.js
+++ b/lib/api/_loaders/assertion-scheduler.js
@@ -138,19 +138,17 @@ class AssertionScheduler {
         .then(() => {
           Utils.makePromise(this.instance.doneCallback, this, [resolveValue, this.instance]);
         })
-        .then(_ => {
-          if (resolveValue.passed) {
-            this.deferred.resolve(resolveValue);
-          } else {
-            this.deferred.reject(resolveValue.err);
-          }
-
-          return resolveValue;
-        })
         .then(_ => {
           if (testError && testError.name !== 'NoSuchElementError') {
             this.opts.reporter.registerTestError(testError);
           }
+          setTimeout(()=> {
+            if (resolveValue.passed) {
+              this.deferred.resolve(resolveValue);
+            } else {
+              this.deferred.reject(resolveValue.err);
+            }
+          });
         });
     }.bind(this), this.instance);
   }
diff --git a/lib/api/_loaders/static.js b/lib/api/_loaders/static.js
index 95b2443f..fc1ee08d 100644
--- a/lib/api/_loaders/static.js
+++ b/lib/api/_loaders/static.js
@@ -8,6 +8,8 @@ const chaiExpect = chai.expect;
 const {flag} = chai.util;
 const {AssertionRunner} = require('../../assertion');
 
+let __last_deferred__ = null;
+
 module.exports = class StaticAssert {
   static get assertOperators() {
     return {
@@ -27,6 +29,14 @@ module.exports = class StaticAssert {
     };
   }
 
+  static get lastDeferred() {
+    return __last_deferred__;
+  }
+
+  static set lastDeferred(value) {
+    __last_deferred__ = value;
+  }
+
   get api() {
     return this.nightwatchInstance.api;
   }
@@ -55,13 +65,14 @@ module.exports = class StaticAssert {
       constructor({negate, args}) {
         super();
 
+        StaticAssert.lastDeferred = null;
         this.negate = negate;
         this.args = args;
         this.passed = null;
         this.expected = null;
         this.actual = null;
-        let lastArgument = args[args.length - 1];
-        let isLastArgString = Utils.isString(lastArgument);
+        const lastArgument = args[args.length - 1];
+        const isLastArgString = Utils.isString(lastArgument);
         this.message = isLastArgString && (args.length > 2 || Utils.isBoolean(args[0])) && lastArgument ||
           Utils.isFunction(args[0]) && '[Function]';
       }
@@ -146,9 +157,16 @@ module.exports = class StaticAssert {
         isES6Async
       });
 
-      if (isES6Async) {
+      if (isES6Async || node.isES6Async) {
+        StaticAssert.lastDeferred = deferred;
+
         Object.assign(node.deferred.promise, this.api);
 
+        //prevent unhandled rejection        
+        node.deferred.promise.catch(err => {
+          return StaticAssert.lastDeferred.reject(err);
+        });
+
         return node.deferred.promise;
       }
 
diff --git a/lib/core/asynctree.js b/lib/core/asynctree.js
index 34e6b9fe..bf593edf 100644
--- a/lib/core/asynctree.js
+++ b/lib/core/asynctree.js
@@ -88,7 +88,7 @@ class AsyncTree extends EventEmitter{
   }
 
   shouldRejectNodePromise(err) {
-    if (err.isExpect && this.currentNode.isES6Async) {
+    if ((err.isExpect|| this.currentNode.namespace === 'assert') && this.currentNode.isES6Async) {
       return true;
     }
 
@@ -105,7 +105,7 @@ class AsyncTree extends EventEmitter{
       return false;
     }
 
-    return err.name === 'NightwatchAssertError' && !err.isExpect && !parent.isRootNode && parent.isES6Async;
+    return err.name !== 'NightwatchAssertError' && !err.isExpect && !parent.isRootNode && parent.isES6Async;
   }
 
   async runChildNode(node) {
diff --git a/lib/transport/selenium-webdriver/browserstack.js b/lib/transport/selenium-webdriver/browserstack.js
index 56e87ea1..1e1c5031 100644
--- a/lib/transport/selenium-webdriver/browserstack.js
+++ b/lib/transport/selenium-webdriver/browserstack.js
@@ -1,6 +1,7 @@
 const stripAnsi = require('strip-ansi');
 const {Logger} = require('../../utils');
 const BaseDriver = require('./mobile-webdriver.js');
+const defaultsDeep = require('lodash.defaultsdeep');
 
 class Browserstack extends BaseDriver {
   get ApiUrl() {
@@ -9,19 +10,19 @@ class Browserstack extends BaseDriver {
 
 
   get accessKey() {
-    return this.bstackOptions.accessKey;
+    return this.settings.desiredCapabilities['bstack:options'].accessKey;
   }
 
   get username() {
-    return this.bstackOptions.userName;
+    return this.settings.desiredCapabilities['bstack:options'].userName;
   }
 
   get build() {
-    return this.bstackOptions.buildName;
+    return this.settings.desiredCapabilities['bstack:options'].buildName;
   }
 
   get local() {
-    return this.bstackOptions.local;
+    return this.settings.desiredCapabilities['bstack:options'].local;
   }
 
   constructor(nightwatchInstance, browserName) {
@@ -48,31 +49,29 @@ class Browserstack extends BaseDriver {
 
     const {desiredCapabilities} = this.settings;
     //checking for legacy-ways for providing config
-    this.bstackOptions = {
+    this.settings.desiredCapabilities['bstack:options'] = defaultsDeep(this.settings.desiredCapabilities['bstack:options'], {
       userName: desiredCapabilities['browserstack.user'], 
       accessKey: desiredCapabilities['browserstack.key'], 
-      buildName: desiredCapabilities.build, 
+      buildName: desiredCapabilities.build,
       local: desiredCapabilities['browserstack.local']
-    };
-
-    Object.assign(this.bstackOptions, this.settings.desiredCapabilities['bstack:options']);
-
+    });
 
     if (!this.accessKey && process.env.BROWSERSTACK_KEY) {
-      this.bstackOptions.accessKey = process.env.BROWSERSTACK_KEY;
+      this.settings.desiredCapabilities['bstack:options'].accessKey = process.env.BROWSERSTACK_KEY;
     }
 
     if (!this.username && process.env.BROWSERSTACK_USER) {
-      this.bstackOptions.userName = process.env.BROWSERSTACK_USER;
+      this.settings.desiredCapabilities['bstack:options'].userName = process.env.BROWSERSTACK_USER;
     }
 
     if (!this.build) {
-      this.bstackOptions.buildName = 'nightwatch-test-build';
+      this.settings.desiredCapabilities['bstack:options'].buildName = 'nightwatch-test-build';
     }
 
     if (this.local) {
       this.useLocal = true;
     }
+
   }
 
   verifySettings() {


Test patch:
diff --git a/test/apidemos/custom-commands/testUsingAsyncCustomAssert.js b/test/apidemos/custom-commands/testUsingAsyncCustomAssert.js
new file mode 100644
index 00000000..2d4ae710
--- /dev/null
+++ b/test/apidemos/custom-commands/testUsingAsyncCustomAssert.js
@@ -0,0 +1,5 @@
+describe('custom command using assert', function () {
+  it('element visible using custom command', async function() {
+    await browser.customVisible('#weblogin');
+  });
+});
\ No newline at end of file
diff --git a/test/extra/commands/es6async/customVisible.js b/test/extra/commands/es6async/customVisible.js
new file mode 100644
index 00000000..5fbdab19
--- /dev/null
+++ b/test/extra/commands/es6async/customVisible.js
@@ -0,0 +1,5 @@
+module.exports = class customVisible {
+  async command(selector) {
+    await this.api.assert.visible(selector);
+  }
+};
\ No newline at end of file
diff --git a/test/lib/command-mocks.js b/test/lib/command-mocks.js
index 07897d36..0bfd7043 100644
--- a/test/lib/command-mocks.js
+++ b/test/lib/command-mocks.js
@@ -204,6 +204,16 @@ module.exports = {
     return this;
   },
 
+  w3cVisible(value = true) {
+    MockServer.addMock({
+      url: '/session/13521-10219-202/execute/sync',
+      method: 'POST',
+      response: JSON.stringify({
+        value
+      })
+    }, true);
+  }, 
+
   findElements({using = 'css selector', value = '#container', response = null, times = 0}) {
     const mockOpts = {
       url: '/session/13521-10219-202/elements',
diff --git a/test/sampletests/es6await/selenium/basicSampleTestSelenium.js b/test/sampletests/es6await/selenium/basicSampleTestSelenium.js
index 0bea4888..8a3e2a9e 100644
--- a/test/sampletests/es6await/selenium/basicSampleTestSelenium.js
+++ b/test/sampletests/es6await/selenium/basicSampleTestSelenium.js
@@ -10,7 +10,7 @@ describe('basicSampleTest', function() {
       assert.deepStrictEqual(result, {value: [{ELEMENT: '0'}], status: 0, returned: 1, passed: true});
     });
 
-    assert.deepStrictEqual(assertResult, {value: [{ELEMENT: '0'}], status: 0, returned: 1, passed: true});
+    assert.deepStrictEqual(assertResult, [{ELEMENT: '0'}]);
 
     await browser.end();
   });
diff --git a/test/sampletests/suiteretries/locate-strategy/suiteRetriesLocateStrategy.js b/test/sampletests/suiteretries/locate-strategy/suiteRetriesLocateStrategy.js
index 11e72ddb..9240f2a5 100644
--- a/test/sampletests/suiteretries/locate-strategy/suiteRetriesLocateStrategy.js
+++ b/test/sampletests/suiteretries/locate-strategy/suiteRetriesLocateStrategy.js
@@ -20,7 +20,8 @@ module.exports = {
       .perform(function() {
         if (failFirstTime) {
           failFirstTime = false;
-          client.assert.ok(false);
+
+          return client.assert.ok(false);
         }
       });
   }
diff --git a/test/src/apidemos/custom-commands/testCustomCommandsAsync.js b/test/src/apidemos/custom-commands/testCustomCommandsAsync.js
index 2f8c7ebf..7fedf590 100644
--- a/test/src/apidemos/custom-commands/testCustomCommandsAsync.js
+++ b/test/src/apidemos/custom-commands/testCustomCommandsAsync.js
@@ -39,11 +39,41 @@ describe('custom commands with findElements es6 async', function() {
 
     return NightwatchClient.runTests(testsPath, settings({
       output: false,
+      silent: true,
       selenium_host: null,
       custom_commands_path: [path.join(__dirname, '../../../extra/commands/es6async')],
       globals
     }));
   });
 
+  it('custom assert visible es6 async', function() {
+    const testsPath = path.join(__dirname, '../../../apidemos/custom-commands/testUsingAsyncCustomAssert.js');
+    
+    Mocks.createNewW3CSession({
+      testName: 'custom command using assert'
+    });
+
+    Mocks.w3cVisible(true);
+
+    const globals = {
+      waitForConditionPollInterval: 50,
+      waitForConditionTimeout: 120,
+      retryAssertionTimeout: 1000,
+
+      reporter(results) {
+        if (results.lastError) {
+          throw results.lastError;
+        }
+      }
+    };
+
+    return NightwatchClient.runTests(testsPath, settings({
+      output: false,
+      silent: true,
+      selenium_host: null,
+      custom_commands_path: [path.join(__dirname, '../../../extra/commands/es6async')],
+      globals
+    }));
+  });
 
-});
+});
\ No newline at end of file
diff --git a/test/src/index/transport/testBrowserstackTransport.js b/test/src/index/transport/testBrowserstackTransport.js
index 4df9aa4d..04564761 100644
--- a/test/src/index/transport/testBrowserstackTransport.js
+++ b/test/src/index/transport/testBrowserstackTransport.js
@@ -65,6 +65,32 @@ describe('BrowserstackTransport', function () {
     delete process.env['KEY'];
   });
 
+  it('test create Transport for Browserstack - empty buildName', function() {
+    process.env['USER'] = 'test-access-user';
+    process.env['KEY'] = 'test-access-key';
+
+    const client = NightwatchClient.client({
+      webdriver: {
+        host: 'hub-cloud.browserstack.com',
+        port: 443
+      },
+      desiredCapabilities: {
+        'browserstack.user': '${USER}',
+        'browserstack.key': '${KEY}'
+      }
+    });
+
+    const {transport} = client;
+    assert.ok(transport instanceof SeleniumRemote);
+    assert.strictEqual(transport.username, 'test-access-user');
+    assert.strictEqual(transport.accessKey, 'test-access-key');
+    assert.strictEqual(transport.build, 'nightwatch-test-build');
+
+    delete process.env['USER'];
+    delete process.env['KEY'];
+
+  });
+  
   it('test create Transport for Browserstack', function(done) {
     const client = NightwatchClient.client({
       webdriver: {