Skip to end of metadata
Go to start of metadata

With our support for the latest Selenium version, 3.11.0, Sauce Labs also now supports the W3C-compliant Selenium capabilities and protocol that will be released with upcoming Selenium versions. Some of the features being implemented are only available when using the W3C protocol, and the upcoming Selenium versions will include extended capabilities that are not backwards-compatible with previous Selenium versions. Sauce Labs is offering a Beta support program to test these new features, and to help prepare for the transition to the upcoming Selenium versions. In addition to feedback about updating your scripts as described in this topic, we'd like to hear your feedback about the overall changes to Selenium in our dedicated Slack channel. If you would like to apply to be part of the Beta Slack channel, please contact our Product Team

W3C Protocol for Appium

Sauce labs will launch a separate initiative to support the W3C protocol for Appium. Appium 1.8.0, released on April 20th, 2018 offers full support for W3C. We are not aware of any existing issues with using W3C capabilities in Appium tests, however we will launch a separate initiative to offer Beta support for W3C capabilities for Appium tests on the Sauce Labs cloud. 

Updating Desired Capabilities

You'll need to make a few changes to the desired capabilities of your existing Selenium test scripts to use the new W3C capabilities in Selenium 3.11.0.

Change the name of the capability to browserVersion and set the version to latest, or use one of these browser versions that is compatible with the W3C protocol:

  • Firefox - v.53+
  • Chrome - v.61+
  • Internet Explorer 11

A new capability in which you must include all the capabilities that are specific to Sauce Labs.

For example, if you wanted to specify your Sauce username, access key, and the Selenium version in your test, you would set the sauce:options like this:

"sauce:options": {"username": "myuser", "accesskey": "XXXXXXXX", "seleniumVersion": "3.11.0"}

Set a Value for seleniumVersion

When using sauce:options, you must include the seleniumVersion capability, and set a value for it, as shown in the example. If you don't include this capability, your test will fail with an error like Sauce VMs failed to start the browser or device Details Browser = IE11, Windows 7 - metadata shows “sauce:options”: “oversized non-string {…}.

A new capability in which you must include all the capabilities that are specific to Sauce Labs.

For example, if you wanted to specify your Sauce username, access key, and the Selenium version in your test, you would set the sauce:options like this:

"sauce:options": {"username": "myuser", "accesskey": "XXXXXXXX", "seleniumVersion": "3.11.0"}

The capabilities that are specific to Sauce Labs are:

    • accessKey
    • appiumVersion
    • avoidProxy
    • build
    • captureHtml
    • chromedriverVersion
    • commandTimeout
    • crmuxdriverVersion
    • customData
    • disablePopupHandler
    • extendedDebugging
    • firefoxAdapterVersion
    • firefoxProfileUrl
    • idleTimeout
    • iedriverVersion
    • maxDuration
    • name
    • parentTunnel
    • passed
    • prerun
    • preventRequeue
    • priority
    • proxyHost
    • public
    • recordLogs
    • recordScreenshots
    • recordVideo
    • restrictedPublicInfo
    • screenResolution
    • seleniumVersion
    • source
    • tags
    • timeZone
    • tunnelIdentifier
    • username
    • videoUploadOnPass
This should now be set only within the sauce:options capability. For tests running on Google Chrome, seleniumVersion does not need to be set at all.
Change the capability name to platformName
For testing on Google Chrome browsers, change chrome to googlechrome

For tests on Google Chrome, the W3C capability must be set as an experimental option:

ChromeOptions chOpts = new ChromeOptions(); 
chOpts.setExperimentalOption("w3c", true);

This capability needs to be sent if testing in Chrome with W3C.
Additionally, the "w3c" value needs to be set as a boolean value and not a string. For example, it would be set to true in Java and True in Python, not "true."

Change to new.FireFoxOptions(). DesiredCapabilities.firefox is being deprecated, and when you use this capability with Selenium 3.11, you'll see a message: "INFO: Using `new FirefoxOptions()` is preferred to `DesiredCapabilities.firefox()"
Set 'iedriverVersion' to 3.12.0

Sample Code Snippets

You can find sample code snippets for a variety of language/framework combinations in our training repository on GitHub

 Click here to expand the Java example

import org.openqa.selenium.WebDriver;
import org.testng.ITestResult;
import org.testng.annotations.*;
import org.testng.asserts.*;
import org.openqa.selenium.MutableCapabilities;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.openqa.selenium.JavascriptExecutor;

import java.lang.reflect.Method;
import java.net.MalformedURLException;
import java.net.URL;

public class W3CFirefoxTest {
    protected WebDriver driver;
    
    /**
         * @BeforeMethod is a TestNG annotation that defines specific prerequisite test method behaviors.
            In the example below we:
            - Define Environment Variables for Sauce Credentials ("SAUCE_USERNAME" and "SAUCE_ACCESS_KEY")
            - Define Firefox Options such as W3C protocol
            - Define the "sauce:options" capabilities, indicated by the "sauceOpts" MutableCapability object
            - Define the WebDriver capabilities, indicated by the "caps" DesiredCapabilities object
            - Define the service URL for communicating with SauceLabs.com indicated by "sauceURL" string
            - Set the URL to sauceURl
            - Set the driver instance to a RemoteWebDriver
            - Pass "url" and "caps" as parameters of the RemoteWebDriver
            For more information visit the docs: http://static.javadoc.io/org.testng/testng/6.9.4/org/testng/annotations/BeforeMethod.html
    */
    @BeforeMethod
    public void setup(Method method) throws MalformedURLException {
        String username = System.getenv("SAUCE_USERNAME");
        String accessKey = System.getenv("SAUCE_ACCESS_KEY");
        String methodName = method.getName();
        
        /** FirefoxOptions allows us to set browser-specific behavior such as profile settings, headless capabilities, insecure tls certs, 
        and in this example--the W3C protocol 
        For more information see: https://seleniumhq.github.io/selenium/docs/api/java/org/openqa/selenium/firefox/FirefoxOptions.html */
        
        FirefoxOptions foxOpts = new FirefoxOptions();
        foxOpts.setCapability("w3c", true);

       /** The MutableCapabilities class  came into existence with Selenium 3.6.0 and acts as the parent class for 
        all browser implementations--including the FirefoxOptions class extension.
        Fore more information see: https://seleniumhq.github.io/selenium/docs/api/java/org/openqa/selenium/MutableCapabilities.html */
        
        MutableCapabilities sauceOpts = new MutableCapabilities();
        sauceOpts.setCapability("name", methodName);
        sauceOpts.setCapability("seleniumVersion", "3.141.59");
        sauceOpts.setCapability("username", username);
        sauceOpts.setCapability("accessKey", accessKey);
        sauceOpts.setCapability("tags", "w3c-chrome-tests")
        
        /** Below we see the use of our other capability objects, 'foxOpts' and 'sauceOpts', 
        defined in 'moz:firefoxOptions' and sauce:options respectively.
        */
        DesiredCapabilities caps = new DesiredCapabilities();
        caps.setCapability("moz:firefoxOptions",  foxOpts);
        caps.setCapability("sauce:options", sauceOpts);
        caps.setCapability("browserName", "firefox");
        caps.setCapability("browserVersion", "64.0");
        caps.setCapability("platformName", "windows 10");
        
        /** Finally, we pass our DesiredCapabilities object 'caps' as a parameter of our RemoteWebDriver instance */
        String sauceUrl = "https://ondemand.saucelabs.com:443/wd/hub";
        URL url = new URL(sauceUrl);
        driver = new RemoteWebDriver(url, caps);
    }
    
    /**
         * @Test is a TestNG annotation that defines the actual test case, along with the test execution commands.
            In the example below we:
            - Navigate to our SUT (site under test), 'https://www.saucedemo.com'
            - Store the current page title in a String called 'getTitle'
            - Assert that the page title equals "Swag Labs"
            For more information visit the docs: http://static.javadoc.io/org.testng/testng/6.9.4/org/testng/annotations/Test.html
    */
    @Test
    public void w3cFirefoxTest() throws AssertionError {
        driver.navigate().to("https://www.saucedemo.com");
        String getTitle = driver.getTitle();
        Assert.assertEquals(getTitle, "Swag Labs");
    }
    /**
         * @AfterMethod is a TestNG annotation that defines any postrequisite test method tasks .
            In the example below we:
            - Pass the ITestResult class results to a parameter called 'result'
            - Use the JavascriptExecutor class to send our test 'result' to Sauce Labs with a "passed" flag
                if the test was successful, or a "failed" flag if the test was unsuccessful.
            - Teardown the RemoteWebDriver session with a 'driver.quit()' command so that the test VM doesn't hang.
            For more information visit the docs: http://static.javadoc.io/org.testng/testng/6.9.4/org/testng/annotations/AfterMethod.html
    */
    @AfterMethod
    public void teardown(ITestResult result) {
        ((JavascriptExecutor)driver).executeScript("sauce:job-result=" + (result.isSuccess() ? "passed" : "failed"));
        driver.quit();
    }
}

 Click here to expand the Python Example

import pytest
import os
from selenium import webdriver
from _pytest.runner import runtestprotocol


@pytest.fixture
def driver(request):
    sauce_username = os.environ["SAUCE_USERNAME"]
    sauce_access_key = os.environ["SAUCE_ACCESS_KEY"]
    remote_url = "http://{}:{}@ondemand.saucelabs.com/wd/hub".format(sauce_username, sauce_access_key)

    sauceOptions = {
        "screenResolution": "1280x768",
        "platformName": "Windows 10",
        "browserVersion": "60.0",
        "seleniumVersion": "3.11.0",
        'name': 'Pytest Firefox W3C Sample'
    }

    caps =  {
        'platformName':"Windows 10",
        'browserName': "firefox",
        'browserVersion': '60.0',
        'sauce:options': sauceOptions
    }

    browser = webdriver.Remote(remote_url, desired_capabilities=caps)
    yield browser
    browser.quit()

def pytest_runtest_protocol(item, nextitem, driver):
    reports = runtestprotocol(item, nextitem=nextitem)
    for report in reports:
        if report.when == 'call':
            driver.execute_script('sauce:job-result={}'.format(report.outcome))
    return True


def test_should_open_safari(driver):
    driver.get("http://www.saucedemo.com")
    actual_title = driver.title
    expected_title = "Swag Labs"
    assert expected_title == actual_title

 Click here to expand the Node.js example

/**
    Here we set our script dependencies (e.g. selenium-webdriver and 'assert'), and we also set some key variables such as:
        - our SauceLabs account credentials
        - the SUT (site under test) url
        - any necessary tags we may use to run test reports or filters
        - the WebDriver session (indicated by 'driver')
*/
var webdriver = require('selenium-webdriver'),
    assert = require('assert'),
    username = process.env.SAUCE_USERNAME,
    accessKey = process.env.SAUCE_ACCESS_KEY,
    /* Change the baseURL to your application URL */
    baseUrl = "https://www.saucedemo.com",
    tags = ["w3c", "demoTest", "w3c-firefox-tests", "nodeTest"],
    driver;
/** 
    We use 'describe' in order to group test methods together. Even though we only have one test case in this example,
    structuring your project this way makes it scalable when you add tests. We can also set global-level test execution parameters such as timeouts
*/
describe('W3C Test', function() {
    this.timeout(40000);
    /**
        'beforeEach' is a Mocha test suite hook that allows us to set any prerequisite test method tasks. In this example we set:
        - SauceLabs.com credentials via username and accessKey
        - Browser to firefox
        - OS platform to Windows 10
        - The name of the test
        - and our "sauce:options" object, here we set other test parameters such as the:
            - selenium version, 
            - the build name/number, 
            - test-level timeouts,
            - test case tags
        For more information on 'beforeEach' consult the docs: https://mochajs.org/api/mocha.suite#beforeEach
    */
    beforeEach(function (done) {
        var testName = this.currentTest.title;
        driver = new webdriver.Builder().withCapabilities({
            "browserName": 'firefox',
            "platform": 'Windows 10',
            "version": '61.0',
            "name": testName.toString(),
            "username": username,
            "accessKey": accessKey,
            "sauce:options": {
                "moz:firefoxOptions": {"wc3":true},
                "maxDuration": 3600,
                "idleTimeout": 1000,
                "seleniumVersion:": '3.11.0',
                "tags": tags,
                "build": 'w3c-sauce-mocha-tests'
            }
        }).usingServer("https://ondemand.saucelabs.com:443/wd/hub").build();

        driver.getSession().then(function (sessionid) {
            driver.sessionID = sessionid.id_;
        });
        done();
    });
    
    /**
        'afterEach' is a Mocha test suite hook that allows us to set any postrequisite test method tasks. In the example below we:
            - Use the JavascriptExecutor class to send our test 'result' to Sauce Labs with a "passed" flag
                if the test was successful, or a "failed" flag if the test was unsuccessful.
            - Teardown the RemoteWebDriver session with a 'driver.quit()' command so that the test VM doesn't hang.
        For more information on 'afterEach' consult the docs: https://mochajs.org/api/mocha.suite#afterEach
    */

    afterEach(function (done) {
        driver.executeScript("sauce:job-result=" + (true ? "passed" : "failed"));
        driver.quit();
        done();
    });
    
    /**
         * 'it' is the Mocha test case that defines the actual test case, along with the test execution commands.
            In the example below we:
            - Navigate to our SUT (site under test), 'https://www.saucedemo.com' indicated by the 'baseUrl' variable.
            - Store the current page title in a String called 'title'
            - Assert that the page title equals "Swag Labs"
            For more information visit the docs: https://mochajs.org/api/test
    */

    it('start-W3C-firefox-session', function (done) {
        driver.get(baseUrl);
        driver.getTitle().then(function (title) {
            console.log("title is: " + title);
            assert(true);
            done();
        });
    });
});

 Click here to expand the C# example

using System;
using System.Collections.Generic;
using NUnit.Framework;
using NUnit.Framework.Interfaces;
using OpenQA.Selenium;
using OpenQA.Selenium.Chrome;
using OpenQA.Selenium.Firefox;
using OpenQA.Selenium.Remote;

namespace SeleniumNunit.SimpleExamples
{
    [TestFixture]
    [Category("Selenium 4 tests")]
    public class NUnitExamples
    {
        private IWebDriver _driver;
        private string _sauceUsername;
        private string _sauceAccessKey;

        /// <summary>
        /// This attribute is to identify methods that are called once prior to executing any of the tests in a fixture. 
        /// For more information: https://github.com/nunit/docs/wiki/OneTimeSetUp-Attribute
        /// </summary>
        [OneTimeSetUp]
        public void OneTimeSetup()
        {
            //TODO please supply your Sauce Labs user name in an environment variable
            _sauceUsername = Environment.GetEnvironmentVariable("SAUCE_USERNAME", EnvironmentVariableTarget.User);

            //TODO please supply your own Sauce Labs access Key in an environment variable
            _sauceAccessKey = Environment.GetEnvironmentVariable("SAUCE_ACCESS_KEY", EnvironmentVariableTarget.User);
        }

        /// <summary>
        /// This attribute is used inside a TestFixture to provide a common set of functions that are performed just before each test method is called.
        /// For more information: https://github.com/nunit/docs/wiki/SetUp-Attribute
        /// </summary>
        [SetUp]
        public void SetUp()
        {
            //TODO Add common functionality for each test setup
        }

        /// <summary>
        /// The Test attribute is one way of marking a method inside a TestFixture class as a test.
        /// For more information: https://github.com/nunit/docs/wiki/Test-Attribute
        /// </summary>
        [Test]
        public void W3CChromeTest()
        {
            var chromeOptions = new ChromeOptions()
            {
                BrowserVersion = "latest",
                PlatformName = "Windows 10",
                UseSpecCompliantProtocol = true
            };
            var sauceOptions = new Dictionary<string, object>
            {
                ["username"] = _sauceUsername,
                ["accessKey"] = _sauceAccessKey,
                ["name"] = TestContext.CurrentContext.Test.Name
            };

            chromeOptions.AddAdditionalCapability("sauce:options", sauceOptions, true);

            _driver = new RemoteWebDriver(new Uri("https://ondemand.saucelabs.com/wd/hub"),
                chromeOptions.ToCapabilities(), TimeSpan.FromSeconds(600));
            _driver.Navigate().GoToUrl("https://www.google.com");
            Assert.Pass();
        }

        /// <summary>
        /// The Test attribute is one way of marking a method inside a TestFixture class as a test.
        /// For more information: https://github.com/nunit/docs/wiki/Test-Attribute
        /// </summary>
        [Test]
        public void W3CFirefoxTest()
        {
            // Set up the browser options
            var ffOptions = new FirefoxOptions();
            ffOptions.PlatformName = "Windows 10";
            ffOptions.BrowserVersion = "latest";

            // Set up the new Sauce Options for C#
            // For more information: https://wiki.saucelabs.com/display/DOCS/Selenium+W3C+Capabilities+Support+-+Beta
            var sauceOptions = new Dictionary<string, object>();
            sauceOptions.Add("username", _sauceUsername);
            sauceOptions.Add("accessKey", _sauceAccessKey);
            sauceOptions.Add("name", TestContext.CurrentContext.Test.Name);

            // seleniumVersion is REQUIRED for any browser other than Chrome
            sauceOptions.Add("seleniumVersion", "3.141.59");

            ffOptions.AddAdditionalCapability("sauce:options", sauceOptions, true);

            // Sauce Lab's endpoint
            var uri = new Uri("http://ondemand.saucelabs.com/wd/hub");

            // Instantiate the driver with the Uri and browser options
            _driver = new RemoteWebDriver(uri, ffOptions);

            _driver.Navigate().GoToUrl("https://www.saucelabs.com");
            StringAssert.Contains("Sauce Labs", _driver.Title);
        }

        /// <summary>
        /// This attribute is used inside a TestFixture to provide a common set of functions that are performed after each test method.
        /// For more infomration: https://github.com/nunit/docs/wiki/TearDown-Attribute
        /// </summary>
        [TearDown]
        public void CleanUpAfterEveryTestMethod()
        {
            //Checks the status of the test and passes the result to the Sauce Labs job
            var passed = TestContext.CurrentContext.Result.Outcome.Status == TestStatus.Passed;
            ((IJavaScriptExecutor)_driver).ExecuteScript("sauce:job-result=" + (passed ? "passed" : "failed"));
            
            _driver?.Quit();
        }
    }
}

Before and After Script Example

These two Java snippets show a comparison between an original script, and the version after it has been edited to use the new W3C capabilities.

Before

DesiredCapabilities caps = DesiredCapabilities.firefox();
 
caps.setCapability("platform", "Windows 10");
caps.setCapability("version", "latest");
caps.setCapability("username", "someuser");
caps.setCapability("accessKey", "00000000-0000-0000-0000-000000000000");
caps.setCapability("seleniumVersion", "3.11.0");
caps.setCapability("name", "my test case");
 
WebDriver driver = new RemoteWebDriver(new URL("https://ondemand.saucelabs.com/wd/hub"), caps);

After

DesiredCapabilities caps = DesiredCapabilities.firefox();

caps.setCapability("platformName", "Windows 10");
caps.setCapability("browserVersion", "latest");
 
MutableCapabilities sauceCaps = new MutableCapabilities();
sauceCaps.setCapability("username", "someuser");
sauceCaps.setCapability("accessKey", "00000000-0000-0000-0000-000000000000");
sauceCaps.setCapability("seleniumVersion", "3.11.0");
sauceCaps.setCapability("name", "my test case");
caps.setCapability("sauce:options", sauceCaps);
        
WebDriver driver = new RemoteWebDriver(new URL("https://ondemand.saucelabs.com/wd/hub"), caps);

Checking for Use of New Capabilities

You can check to see whether your tests are running under the new W3C protocol.

  1. Go to the Test Details page for your test in the Sauce Labs web interface.
  2. Click the Commands tab.
  3. Select the first Post command, which will be Post /session.
  4. Under the screenshot of the command, in the Parameters section, you will see the capabilities that were used in the test. If that line begins with desiredCapabilities, you are running the non-W3C version. If it begins with capabilities, you are running the new W3C-compliant version. 

Webinar and Script Editing Demo Videos

In this demo you'll see how to modify a basic Selenium script written in Java to be compliant with the new W3C protocol.

An introduction to Selenium 4 from Sauce Labs

  • No labels