HeadSpin Documentation
Documentation

Selenium Capabilities

In addition to the standard Selenium capabilities and the W3C WebDriver spec, the Selenium server running on each HeadSpin host supports a number of custom capabilities below. In addition, the HeadSpin Selenium load balancer running in the cloud supports additional capabilities that control device selection and redundancy.

<code class="dcode">browserName</code> capability value for each browser

Browser browserName
Chrome chrome
Microsoft Edge MicrosoftEdge, msedge
Chromium chromium
Brave Browser brave
Firefox firefox
Safari safari

Starting a new selenium session against a chromium based browser and chromedriver on a local host require <code class="dcode">chrome</code> as the <code class="dcode">browserName</code> capability. However, the HeadSpin platform requests a proper <code class="dcode">browserName</code> in the above table to create a new session in order to manage the browser instance on the HeadSpin platform. For example, please set brave as the <code class="dcode">browserName</code> capability value in the capabilities set to start a new selenium session against a Brave Browser instance.

Host capabilities

Capability Description Values
headspin:capture Enable video and network capture. Default false. These capture components can be overriden individually by headspin:capture.video or headspin:capture.network. If set, the individual settings take precedence. true, false
headspin:capture.video Enable video capture. When set, this takes precedence over headspin:capture. Also, headspin:capture does not need to be set for this to take effect. true, false
headspin:capture.video.browser.hwAcceleration Enable hardware acceleration in video capture on an Intel CPU-based Windows machine. This capability improves the host machine's CPU usage for video capture feature during the session, but this capability limits changing the window size dynamically in the session. Please use headspin:initialScreenSize capability to set the browser size instead of calling Selenium window-handling APIs. These APIs will get error responses after starting the session. Default false. true, false
headspin:capture.network Enable network capture. When set, this takes precedence over headspin:capture. Also, headspin:capture does not need to be set for this to take effect. true, false
headspin:capture.ignoreHosts A list of ignored host:port regex patterns. These hosts are ignored from the network capture session. The pattern can be just a host name also, in which case all ports are matched. Please ensure the value escaped properly if it has language/context dependent string such as backslash. e.g. ['abc\.example\.com:443', '.*\.mydomain.com']
headspin:capture.networkConfig Configures the network used by the device during the capture session. Allowed keys are shaping, redirectRules, spoofRules, headerRules. See Network Config below for details of each.
headspin:capture.networkKeepInSessionPatterns Controls whether a destination host:port (or ip:port) is kept in the session after an error. By default any destination with an error (e.g. TLS exception) will be excluded from the session, to allow the app to perform as well as possible going forward. Add glob patterns here to keep a destination with an error in the session, to continue to try to parse the network protocol for that destination. This is a list of globs that must fully match host:port or ip:port. e.g. ['headspin.io:443', '*.headspin.io:443']
headspin:capture.disableHttp2 Prevent the device from using HTTP/2 during network capture. Default false. true, false
headspin:capture.startTimeout Set timeout in seconds to wait for the capture session preparation to be ready as part of a new session creation up to 600 seconds. It is similar to how long the new session creation should wait to prepare capture session via Session API as part of it. Default 300 seconds. 200, "500"
headspin:session.name Set the name of the HeadSpin session. For existing sessions, the name can be updated in the Waterfall UI or via the Session Annotation API. string
headspin:session.description Set the description of the HeadSpin session. For existing sessions, the description can be updated in the Waterfall UI or via the Session Annotation API. string
headspin:sessionTags Tag the session with an array of key, value tags. Tags will only be applied to sessions that have performance capture enabled. e.g. [{"demo": "tag"}, {"hello": "world"}]
headspin:testName Sets the User Flow name of this capture session for Performance Monitoring, where all sessions with the same User Flow name are grouped together. To use this, at least one of the following capture components must be active for the session: video or network capture. For details on adding passed/failed/excluded status on the session, see User Flow Status below. e.g. app_load_test
headspin:testData Add custom measurements to the session. This data will be inserted into the performance test, for this session ID e.g. [{"key":"App Load Time", "value":20, "title": "Custom Metrics", "units": "seconds"}]
headspin:autoLabel Set rules to add custom session labels in session capture. See Applying labels automatically below for details. e.g. 'open headspin url': {'commands': [{'method': 'POST', 'endpoint': '/session/:sessionId/url', 'body': 'headspin.io'}], 'category': 'open url time'}
headspin:controlLock Starting the session with this set to true allows interaction with the device via the remote control UI during the session. This should be used with tools such as Appium Inspector, with which you may manually interact with the device during a session. If this is false, the device will be in view-only mode during the session. If the device is already locked by the user (by accessing it in remote control UI or via API), then an automation session cannot be started. Default false. true, false
headspin:waitForAvailableTimeout Set timeout to wait for a locked device to be available. Defaults to 60 seconds or headspin:newCommandTimeout if provided. e.g. 90
headspin:newCommandTimeout Set request timeout from seleniumserver to each WebDriver which is running behind seleniumserver. Defaults to 900 seconds. e.g. 120
headspin:initialScreenSize Set innerWidth/innerHeight size in the create session process. The WebDriver Set Window API sets outerWidth/outerHeight size, but this capability is for innerWidth/innerHeight. The maximum size depends on the host machine. The width on macOS can be larger than the screen width, but the height cannot. On Windows, both can be up to the screen size. The width and height of the screenshot API result depend on the innerWidth/innerHeight. Our video capture on browsers also depends on it. e.g. {"width": 500, "height": 300}
Capability Description Values
headspin:driverLogLevel Set log level to the WebDriver when it starts. The available format depends on each driver. For example, chromedriver allows one of ALL, DEBUG, INFO, WARNING, SEVERE, OFF. Geckodriver is fatal, error, warn, info, config, debug, trace. e.g. DEBUG (Chromium drivers), debug (Gecko driver)
headspin:enableJSConsoleLog Enable to record the browser JavaScript console log for Firefox and Chromium browsers. In Firefox, the console logs will be part of selenium.log in the capture session. Chromium browsers will be in the device.log. Default false. true, false
headspin:screenshotSource Configure the screenshot source. The available values are default and camera. camera means taking a screenshot via the Camera Device (CD) instead of Appium. This option does not affect taking an element screenshot. Please read A/V Box API about the Camera Device. It returns an error response if it failed to take a screenshot via the Camera Device. The value will be default if the device under test does not have a Camera Device associated with it. Default camera. default, camera
headspin:forceQuitSession Handle a delete session request similar to unlock the device in order to quit the session immediately after reaching the request to the Appium server. For example, driver.quit() quits the session immediately even if the previous commands are waiting for responses. Then, these waiting response requests will get invalid session id responses. This helps to quit a session early while the session has no response commands so long. This behavior is similar to quitting Appium process forcefully in the local Appium run. Default false true,false

For scheme

CapabilityDescriptionValue
headspin:allowFileSchemeAllow file:// scheme as Navigate To command. Defaults to false.true, false
headspin:allowChromeSchemeAllow chrome:// scheme as Navigate To command. Defaults to false.true, false

HeadSpin commands

These HeadSpin commands are designed to be run by the Execute Script interface.

Command Name Description Arguments
headspin:quitSession End the session and optionally set the session's user flow status at the same time. See User Flow Status below. {"status": "[passed|failed|excluded|not_set]"}

Browser logs (<code class="dcode">enableJSConsoleLog</code>)

HeadSpin collects JavaScript console logs when <code class="dcode">headspin:enableJSConsoleLog</code> is enabled in a capture session before ending the session. The log can be downloaded from the Waterfall UI or the Session API. JavaScript console logs are in <code class="dcode">jsconsole.log(</code>1) for Chromium browsers and part of <code class="dcode">selenium.log</code> for Firefox.

To get logs for Chromium browsers, use Selenium's log capture command and specify the <code class="dcode">browser</code> type. If you already accessed the <code class="dcode">browser</code> type log during a session, HeadSpin will only collect the <code class="dcode">browser</code> type log after the command runs. The log capture has the log level <code class="dcode">ALL</code> and sets the <code class="dcode">browser</code> type over the loggingPrefs capability by default.

(1) Note that previously <code class="dcode">device.log</code> was used to save the log data instead of <code class="dcode">jsconsole.log</code>. The <code class="dcode">device.log</code> will be unavailable as the JavaScript console log.

Load balancer capabilities

Capability Description Values
headspin:selector A selector string of the device to use. This takes precedence over browserName and browserVersion. See selectors for the selector syntax. The load balancer will consider all the devices in the pool and use the healthiest that is most available to run the session. browserName will be used as part of sku, and browserVersion will be used as part of os_version. os_version: 80.0.361.62
headspin:requestTimeout Handle a request timeout from AppiumLB to each devices. It affects only when a client communicates with the target Appium server via AppiumLB. Defaults to 1200 seconds (20 minutes). e.g. 120

Limitations

● File download is restricted. Browsers do not download files on to the host machine. This may not be changed using capabilities or DevTools protocols.

● Window size depends on the host machine environment.

Navigate To command accepts below schemes. Please contact us if you want to send other schemes.

  • <code class="dcode">http://</code>.
  • <code class="dcode">https://</code>.
  • <code class="dcode">file://</code> requires <code class="dcode">headspin:allowFileScheme</code> capability.
  • <code class="dcode">chrome://</code> requires <code class="dcode">headspin:allowChromeScheme</code> capability.

● Video content displayed in the Safari browser could be blank due to a limitation of the Safari browser.

● Camera, Microphone, Screen Sharing, Notifications are denied in the Safari browser.

● Customizing the browser's proxy with the `proxy` capability is not supported.

Launching arguments

Below arguments will be ignored on our platform.

● Desktop Chromium based browsers

  • <code class="dcode">--allow-sandbox-debugging</code>
  • <code class="dcode">--allow-no-sandbox-job</code>
  • <code class="dcode">--run-without-sandbox-for-testing</code>
  • <code class="dcode">--no-sandbox-and-elevated</code>
  • <code class="dcode">--no-sandbox</code>
  • <code class="dcode">--restore-last-session</code>
  • <code class="dcode">--enable-web-bluetooth</code>
  • <code class="dcode">--unfiltered-bluetooth-devices</code>
  • <code class="dcode">--disable-webusb-security</code>
  • <code class="dcode">--allow-file-access-from-files</code>
  • <code class="dcode">--enable-local-file-accesses</code>
  • <code class="dcode">--unlimited-storage</code>

Resolving errors

HeadSpin Selenium sessions return errors directly from the underlying Selenium driver without modification. Additionally, the Headspin platform may return the following extra errors:

HTTP status code Error (error) Note How to Resolve
400 invalid argument Request body is invalid or API token in the request is invalid. Make sure the API token is valid or selenium commands are correct. This error could also happen when browserName and browserVersion are incorrect in the capabilities.
403 session not created The device is already locked. Make sure the device under test is not in use by others.
404 invalid session id Cannot find active session id on the host. Run your tests from session that was created.
405 unknown method The request is wrong or not allowed on the host Please contact us if the command had errors on only our platform.
408 timeout The operation did not complete. Retry the command. Increasing timeout using the headspin:newCommandTimeout capability should help.
500 session not created Failed to create a new session. Please contact support if this continues to happen.
500 unknown error An unknown error occurred. Please contact support if this continues to happen.
500 timeout The session has been expired. Run your tests from session creation again.

Setting the Selenium versions

Check available Browser versions

HeadSpin host provides the list of available browser versions as API. It helps to confirm which browser versions can run on the host machine.

Route Method
https://{headspin-host}:{headspin-port}/v0/{your-api-token}/versions GET

Example


curl -X GET https://proxy-jp-tyo-1.headspin.io:7001/v0/{your-api-token}/versions

Response


{
    "value": {
        "default": {
            "chrome": "78.0.3904.108", "firefox": "70.0.1", "safari": "12", "microsoftedge": "78.0.250.1"},
            "available": {
                "chrome": {"76.0.3809.126": "76.0.3809.126", "77.0.3865.10": "77.0.0.0"},
                "firefox": {"70.0.1": "0.26.0"},
                "microsoftedge": {"78.0.250.1": "78.0.250.1", "77.0.237.0": "77.0.237.0"},
                "safari": {"12": "12"}
            }
    }
}

The <code class="dcode">available</code> is available browser versions. You can specify them with <code class="dcode">browserName</code> and <code class="dcode">browserVersion</code>. The <code class="dcode">default</code> is chosen if a create session capabilities has no <code class="dcode">browserVersion</code>.

Please contact us if you would like to use a version which is not in the list.

Network Config

Key Name Description Values
shaping (Chromium browsers only) Network conditioning targets. Rate targets are upper bounds on the native link speed. Round trip time and packet loss are in addition to the behavior of the native link. All values must be zero or positive. down is the download rate in megabits per second (mbps). up is the upload rate in megabits per second (mbps). rtt is the round trip time in millisecond for latency. e.g. {"down": 5.1, "up": 1.2, "rtt": 10}
redirectRules A list of rules host_regex=destination_host. If the host regex matches a host, the request will be rewritten as if the client sent it to destination_host instead. Backtick back references are allowed in the destination host. e.g. ["foo\.com=bar.com", "(.*)headspin\.io=\1headspin.com"]
spoofRules A list of rules host_regex=destination_host. If the host regex matches a host, the request IP will be changed to the IP resolved by destination host, as if the DNS record for the original host were changed to the destination host's. e.g. ["foo\.com=13.33.148.190", ".*\.headspin.io=13.33.148.51"]
headerRules A list of rules host_regex=header:value. If the host regex matches, the header will be injected into the request. Multiple headers of the same name will be comma separated in the final request. Backtick back references are allowed in the header and value. e.g. [".*=X-Custom:MyApp"]

User Flow Status

To mark sessions passed, failed, or in some error state, you can either use a HeadSpin Selenium command to end the session, or use the Performance Monitoring API at any time. In either case, the session must be attached to a user flow by specifying <code class="dcode">headspin:testName</code> (this in turn requires that capture is turned on for the session, see description in the Selenium capabilities section).

Valid user flow status strings are: <code class="dcode">passed</code>, <code class="dcode">failed</code>, <code class="dcode">excluded</code>, and <code class="dcode">not_set</code>.

Set user flow status using the <code class="dcode">headspin:quitSession</code> command

  1. Set <code class="dcode">headspin:testName</code> when starting the session. This is required for the next step to work.
  2. End the session by sending the command <code class="dcode">headspin:quitSession</code> with the argument <code class="dcode">{"status": <user flow status>}</code>.

For example, the Python script below sets the session's status to <code class="dcode">excluded</code>:


from selenium import webdriver

caps = {
    ...  # Other capabilities
    "headspin:testName": "test user flow",  # Required to link session to user flow
    "headspin:capture": True                # Required to have a capture session
}

driver = webdriver.Remote('<Web Driver URL>', caps)

# Perform tests
...

response = driver.execute_script('headspin:quitSession', {'status': 'excluded'})

This will end the session and set its user flow status at the same time. It can be used in place of the <code class="dcode">driver.quit()</code> command to end the session. When called without any argument, it has the same effect as <code class="dcode">driver.quit()</code>.

If the command is successful, there will be no return value (<code class="dcode">response is None</code> is <code class="dcode">True</code>). However, if an argument is given but it could not be processed into a valid user flow status, then a string containing information about the problem will be returned. The session will still end, but no user flow status will be set.

Set user flow status using Performance Monitoring API

  1. Set <code class="dcode">headspin:testName</code> when starting the session, or link the session to a user flow after it has started using the Performance Monitoring API.
  2. POST to the Performance Monitoring API to set the status of the session, using the session ID from the driver.

For example, the Python script below sets the session's status to <code class="dcode">passed</code> using <code class="dcode">requests</code> to post to the API:


import requests
from selenium import webdriver
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities

# Start a session with capture
driver = webdriver.Remote(command_executor=url, desired_capabilities=capabilities)

# Set api_token in the header
headers = {
    'Authorization': 'Bearer <your_api_token>'
}

perf_data = {
    'session_id': driver.session_id,
    'status': 'passed'
}
requests.post('https://api-dev.headspin.io/v0/perftests/upload', headers=headers, json=perf_data)

Applying labels automatically

<code class="dcode">headspin:autoLabel</code> allows a session to add session annotations without separate session annotation API calls. This feature starts a tracking timer when a request reaches a pbox or the pbox gets a response from the WebDriver running on the pbox. If the pbox already has a running tracking timer with the same label name, the pbox will end the timer and create a new label using the given label name.

The diagram below shows how a pbox starts a tracking timer when it receives a request and stops the timer when the pbox handles the response.


client                  Pbox               WebDriver
    |------request------> |
    |               [starts timer]              |
    |                     | -----request------> |
    |                     |                     |
    |                     | <----response------ |
    |                [ends timer]
    |<-----response-------|

Keys

<code class="dcode">headspin:autoLabel</code> has the structure below. The top key is a label name you want to create. The value contains rules to match which requests should be labeled with the provided name. Keys and values surrounded by <code class="dcode">&lt;&gt;</code> can be customized.


{
  "": {
    "onCommand": [
        {
          "method": "<HTTP request method like GET>",
          "endpoint": "<WebDriver command expected to match like /session/:sessionId/title>"
        },
        {
          "method": "<HTTP request method like POST>",
          "endpoint": "<WebDriver command expected to match like /session/:sessionId/url>",
          "body": "<Expected string to be match with as a regular expression>"
        },
        #...
    ],
    "category": "<category name>"
  }
}

The top level key will be the label name.

Key Name Description Values
<your label name> A string that will be the label name. The value is JSON Object which has the below items. {"my test label": {"onCommandStart": [...], ...}}

The value of the above label name configures the rule.

Key Name Description Values
onCommand An array to control labeling rule. Commands in this key works on both timing,onCommandStart and onCommandEnd. See the below Commands for the details. [{"method": "GET", "endpoint: "/session/:sessionId/title"}, ...]
onCommandStart An array to control labeling rule. See the below Commands for the details. [{"method": "GET", "endpoint: "/session/:sessionId/title"}, ...]
onCommandEnd An array to control labeling rule. See the below Commands for the details. [{"method": "GET", "endpoint: "/session/:sessionId/title"}, ...]
label_type (Optional, default user) A string that is the type of the label. The label type determines how HeadSpin responds to the label. See Available session label types in Session Annotation API for details. user
category (Optional) A string that is the category of the label. The label category is converted to lower case. my labels
data (Optional) Any useful JSON-serializable content associated with this label. {"my": "data"}
pinned (Optional, default false) A boolean flag indicating whether the label is pinned to the session or not. Pinned labels are shown by default when viewing a session, under the right panel's Details section. Pinned labels cannot be deleted. false
video_box (Optional) Coordinates of bounding boxes provided as nested arrays in the format [[x0, y0, x1, y1], ...]. See the Applying spatial filtering in video analyses in Session Annotation API for details. [[0,0,100,200], [0,0,500,800]]

Labeling rules

<code class="dcode">onCommand</code>, <code class="dcode">onCommandStart</code> and <code class="dcode">onCommandEnd</code> define when the label is created with what rules.

The below sequence indicates when each command key is called. <code class="dcode">onCommandStart</code> is when the pbox gets a request. <code class="dcode">onCommandEnd</code> is when the WebDriver returns a request to the pbox. onCommand includes both cases. This time period by onCommand should be the same as labels in <code class="dcode">selenium-commands</code> category on a captured session.


client                  Pbox               WebDriver
    |------request------> |
    |              [onCommandStart]             |
    |                     | -----request------> |
    |                     |                     |
    |                     | <----response------ |
    |               [onCommandEnd]
    |<-----response-------|

<code class="dcode">headspin:autoLabel</code> detects a command if the command should be labeled automatically by checking its HTTP request <code class="dcode">method</code>, the <code class="dcode">endpoint</code>, and the <code class="dcode">body</code>:

Key Name Description Values
method A string that is http request method. GET, POST
endpoint A string that is http request path. The format follows WebDriver endpoint defined in W3C or JsonWireProtocol. The string can have placeholders to handle arbitrary string part like session id in the path. For example, :sessionId is the placeholder of the {session id} in WebDriver endpoint defined in W3C or :sessionId in JsonWireProtocol. Available placeholders are :sessionId, :elementId, :name, :propertyName, :windowHandle (only JsonWireProtocol), :other (only JsonWireProtocol) and :key (only JsonWireProtocol). /session/:sessionId/url
body (Optional) A string to search the string as a regular expression in the http request body. subdomain.headspin.io/.*

Example

<code class="dcode">onCommandStart</code>

The below example only has <code class="dcode">onCommandStart</code>. It means the pbox starts or ends and creates a label when matched requests come to the pbox.


# Ruby
firefox = Selenium::WebDriver.for(:remote,
  url: 'https://{headspin-host}:{headspin-port}/v0/{your-api-token}/wd/hub',
  desired_capabilities: { browserName: 'firefox',  'headspin:capture': true,
    'headspin:autoLabel': {
      'Do something test-automation page': {
        'onCommandStart': [
          {'method': 'POST', 'endpoint': '/session/:sessionId/url', 'body': 'https://www.headspin.io/platform/test-automation/'},
          {'method': 'POST', 'endpoint': '/session/:sessionId/url', 'body': 'https://www.headspin.io/platform/local/'}
        ],
        'category': 'open headspin site',
        'label_type': 'page-load-request'
      }
    }
  }
)

firefox.get 'https://www.headspin.io'

# The pbox starts a tracking timer as 'Do something test-automation page' label name
# when the below request reaches the pbox since the URL matches the first rule
# in 'onCommandStart'.
firefox.get 'https://www.headspin.io/platform/test-automation/'

# do something

# The pbox ends the timer and create a label named 'Do something test-automation page'
# when the below request reaches the pbox since the URL matches the seconds rule
# in 'onCommandStart'.
firefox.get 'https://www.headspin.io/platform/local/'


# do something

# The pbox starts a tracking timer a new label named 'Do something test-automation page'
firefox.get 'https://www.headspin.io/platform/local/'


# The pbox creates a label as 'Do something test-automation page'.
firefox.get 'https://www.headspin.io/platform/test-automation/'

firefox.quit
auto label

<code class="dcode">onCommand</code>

The below is another example with <code class="dcode">onCommand</code>. It means when a command matches to the rule, the pbox labels the command as the given label name, <code class="dcode">Do something test-automation page</code>. The time duration must be the same as the command time duration in <code class="dcode">selenium-commands</code> category.


# Python
firefox = webdriver.Remote(
  'https://{headspin-host}:{headspin-port}/v0/{your-api-token}/wd/hub',
  { 'browserName': 'firefox',  'headspin:capture': True,
    'headspin:autoLabel': {
      'Do something test-automation page': {
        'onCommand': [
          {'method': 'POST', 'endpoint': '/session/:sessionId/url', 'body': 'https://www.headspin.io/'}
        ],
        'category': 'open headspin site',
        'label_type': 'page-load-request'
      }
    }
  }
)

# The pbox starts a tracking timer as 'Do something test-automation page' label name
# when the pbox gets this request.
# The pbox ends the timer when it receives a response by the driver,
# before responding it to the client.
firefox.get('https://www.headspin.io')

# No nothing
firefox.get('https://subdomain.headspin.io/')

# do something

# The pbox starts a tracking timer as 'Do something test-automation page' label name
# when the pbox gets this request.
# The pbox ends the timer when it receives a response by the driver,
# before responding it to the client.
firefox.get('https://www.headspin.io')

firefox.quit()

<code class="dcode">onCommandStart</code> and <code class="dcode">onCommandEnd</code>

The below is combination of <code class="dcode">onCommandStart</code> and <code class="dcode">onCommandEnd</code>. A pbox starts a tracking timer when a request matches either <code class="dcode">onCommandStart</code> or <code class="dcode">onCommandEnd</code>. It stops the timer when a request matches either <code class="dcode">onCommandStart</code> or <code class="dcode">onCommandEnd</code> after the above request.


# Python
firefox = webdriver.Remote(
  'https://{headspin-host}:{headspin-port}/v0/{your-api-token}/wd/hub',
  { 'browserName': 'firefox',  'headspin:capture': True,
    'headspin:autoLabel': {
      'Do something test-automation page': {
        'onCommandStart': [
          {'method': 'POST', 'endpoint': '/session/:sessionId/url', 'body': 'https://www.headspin.io/'}
        ],
        'onCommandEnd': [
          {'method': 'GET', 'endpoint': '/session/:sessionId/element/:elementId/text'}
        ],
        'category': 'open headspin site',
        'label_type': 'page-load-request'
      }
    }
  }
)

# The pbox starts a tracking timer as 'Do something test-automation page' label name
# when the pbox gets this request.
firefox.get('https://www.headspin.io')

# do something

# The pbox ends the timer and create a label named 'Do something test-automation page'
# when the pbox receives the below request against the driver as 'onCommandEnd'.
firefox.title()

# do something

# The pbox starts a tracking timer as 'Do something test-automation page'
# when the pbox receives the below request against the driver as 'onCommandEnd'.
firefox.title()

# do something

# The pbox ends the timer and create a label named 'Do something test-automation page'
# when the pbox receives the below request against the driver as 'onCommandEnd'.
firefox.title()

firefox.quit()

Troubleshooting

  • For Safari 16.4 and higher, including 17, the <code class="dcode">com.apple.WebKit.Networking</code> process can crash when a delete cookies command is issued before opening a URL. From the perspective of the client, it could result in an 'invalid session id' error response to a new session request. To avoid the error, please do not use cookie deletion commands such as <code class="dcode">driver.manage.delete_all_cookies</code> before opening a URL.