The Sauce Labs Cookbook

Sauce Headless

Front End Performance Testing

Insights

External Resources

More Info


Page tree
Skip to end of metadata
Go to start of metadata

Sauce Labs now supports the W3C WebDriver-compliant Selenium capabilities and protocol featured in Selenium version 3.11 and higher. Please note that some extended capabilities are not backwards-compatible with versions prior to 4.0.  

The W3C WebDriver standards were adopted when Selenium achieved its specification as the testing protocol for web applications. As browser vendors update to support W3C WebDriver and shift away from JSON Wire Protocol (JWP), it’s important that you update your tests accordingly. This article will help ensure that your tests are W3C WebDriver-compliant and can successfully execute on Sauce Labs. 

See the following sections for more information:

What You'll Need

To ensure W3C WebDriver compliance:

  • Use Selenium version 3.11 or higher
  • Make the following changes in your WebDriver capabilities:
    • Update legacy JWP desired capability names to reflect the new W3C WebDriver-compliant naming conventions (e.g., platform becomes platformNameversion becomes browserVersion). To see some examples of W3C WebDriver-compliant capabilities (e.g., platformName and browserVersion), head to the official W3C recommendation website.
    • Include our custom sauce:options capabilities in your Sauce Labs test scripts. Some examples are namebuildusernameaccessKey, seleniumVersion

       Click here to see a full list of sauce:options capabilities
      • 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

      More information: Test Configuration Options

NOTE: Your sauce:options capabilities (e.g., name, build) must be bundled together inside the same code block, as seen in this example:


browserName: 'firefox',
platformName: 'macOS 10.15',
browserVersion: 'latest'
sauce:options: {
  name: 'My test name',
  build: 'My build',
  username: "SAUCE_USERNAME",
  accessKey: "SAUCE_ACCESS_KEY"
  seleniumVersion: "3.141.59"
} 

W3C WebDriver Browser Compatibility

By default, Sauce Labs uses older Selenium versions for Firefox, IE, and Safari. This is important to know since newer commands and configurations may not be supported in those versions.

The following browser versions are compatible with the W3C WebDriver protocol:

  • Firefox version 53 and higher
  • Google Chrome version 61 and higher
  • Internet Explorer 11

chromeOptions()

For tests on Google Chrome versions 74 and lower, the W3C WebDriver capability must be set as an experimental option. ChromeDriver version 75 runs in W3C WebDriver standard compliant mode by default, so setting this capability won't be necessary in the future. Here's an example:

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

NOTEw3c must be set as a boolean value (e.g., true in Java and True in Python) – not a string (e.g., "true").

Verifying Capabilities for W3C WebDriver Compliance

Here's how to verify if your tests are running under the new W3C WebDriver protocol:

  1. Go to the Test Details page for your test in Sauce Labs.
  2. Click the Commands tab.
  3. Select the first Post command, which will be Post /session.
  4. Under the Parameters section, check the capabilities that are used in the test. 
    • If your Parameters section begins with capabilities, you're running the new W3C WebDriver-compliant version(tick) 


    • If it begins with desiredCapabilities, you're running the legacy, non-W3C WebDriver version(error) 
      Legacy Parameters - Example 

W3C WebDriver-Compliant Language Changes in Selenium 3.11+

There are some changes to specific Selenium language bindings you should be aware of when migrating to the W3C WebDriver protocol. Here is an example:

In Selenium version 3.11 and higher, be sure to input the new DriverOptions() class, which is used to manage options specific to each browser web driver.

Example: Selenium 3.11+, with DriverOptions() (tick)

FireFoxOptions mozOpts = new FirefoxOptions();

Example: Legacy, with DesiredCapabilities() (error)

DesiredCapabilities caps = new DesiredCapabilities.firefox();

Using legacy formatting in Selenium 3.11+ script will yield the following message:

"INFO: Using `new FirefoxOptions()` is preferred to `DesiredCapabilities.firefox()"

You can now set capabilities using the MutableCapabilities() class instead of using DesiredCapabilities().

MutableCapabilities() is the preferred method; it implements all interfaces, including DriverOptions() and DesiredCapabilities(). For more information, see the DriverOptions class Selenium documentation.

These two Java snippets show a comparison between a legacy script and a version edited to use the new W3C WebDriver capabilities:

Example: Selenium 3.11+, with MutableCapabilities() (tick)

MutableCapabilities sauceCaps = new MutableCapabilities();
sauceCaps.setCapability("username", "someuser");
sauceCaps.setCapability("accessKey", "00000000-0000-0000-0000-000000000000");
sauceCaps.setCapability("name", "my test case");

MutableCapabilities caps = new MutableCapabilities();
caps.setCapability("sauce:options", sauceCaps);
caps.setCapability("platformName", "Windows 10");
caps.setCapability("browserName", "firefox");
caps.setCapability("browserVersion", "latest");
        
WebDriver driver = new RemoteWebDriver(new URL("https://ondemand.saucelabs.com/wd/hub"), caps);

Example: Legacy, with DesiredCapabilities() (error)

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

Instantiating WebDriver with W3C WebDriver-Compliant Capabilities

Select a code snippet below in the programming language of your choice, then follow the instructions. You can find more sample code in the Sauce Labs training repository on GitHub.


 Click here to see the full example

import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.MutableCapabilities;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.testng.Assert;
import org.testng.ITestResult;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;

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

public class TestNGW3CChromeTest {
    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 Chrome 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();

        /** ChomeOptions 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/chrome/ChromeOptions.html */

        ChromeOptions chromeOpts = new ChromeOptions();
        chromeOpts.setExperimentalOption("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 ChromeOptions 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("build", "Java-W3C-Examples");
        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, 'chromeOpts' and 'sauceOpts',
         defined in ChromeOptions.CAPABILITY and sauce:options respectively.
         */
        DesiredCapabilities caps = new DesiredCapabilities();
        caps.setCapability(ChromeOptions.CAPABILITY,  chromeOpts);
        caps.setCapability("sauce:options", sauceOpts);
        caps.setCapability("browserName", "googlechrome");
        caps.setCapability("browserVersion", "latest");
        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 TestNGw3cChromeTest() 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();
    }
}

TestNG Example Walkthrough

  1. Download or clone the script from GitHub.

  2. Ensure you have the prerequisite software.

  3. Resolve any dependencies:

    $ mvn dependency:resolve
  4. Export your Sauce Labs Username and Access Key:

    Sauce Labs Username and Access Key Example:
    export SAUCE_USERNAME=my-sauce-username
    export SAUCE_ACCESS_KEY=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxx
  5. Run the following command:

    $ mvn clean test -Dtest=TestNGW3CChromeTest
 Click here to see the full example

Junit5 W3C Chrome Example
import org.junit.jupiter.api.*;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.MutableCapabilities;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;

import java.net.MalformedURLException;
import java.net.URL;

public class JUnit5W3CChromeTest {
    protected WebDriver driver;
    public Boolean result;

    /**
     * @BeforeEach is a JUnit 5 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 Chrome 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: https://junit.org/junit5/docs/5.0.2/api/org/junit/jupiter/api/BeforeEach.html
     */

    @BeforeEach
    public void setup(TestInfo testInfo) throws MalformedURLException {
        String username = System.getenv("SAUCE_USERNAME");
        String accessKey = System.getenv("SAUCE_ACCESS_KEY");
        String methodName = testInfo.getDisplayName();

        /** ChomeOptions 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/chrome/ChromeOptions.html */

        ChromeOptions chromeOpts = new ChromeOptions();
        chromeOpts.setExperimentalOption("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 ChromeOptions 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("build", "Java-W3C-Examples");
        sauceOpts.setCapability("seleniumVersion", "3.141.59");
        sauceOpts.setCapability("username", username);
        sauceOpts.setCapability("accessKey", accessKey);
        sauceOpts.setCapability("tags", testInfo.getTags());


        /** Below we see the use of our other capability objects, 'chromeOpts' and 'sauceOpts',
         defined in ChromeOptions.CAPABILITY and sauce:options respectively.
         */
        DesiredCapabilities caps = new DesiredCapabilities();
        caps.setCapability(ChromeOptions.CAPABILITY,  chromeOpts);
        caps.setCapability("sauce:options", sauceOpts);
        caps.setCapability("browserName", "googlechrome");
        caps.setCapability("browserVersion", "latest");
        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);
    }
    /**
     * @Tag is a JUnit 5 annotation that defines test method tags that aid in reporting and filtering tests.
    For more information visit the docs: https://junit.org/junit5/docs/5.0.2/api/org/junit/jupiter/api/Tag.html

     */
    @Tag("w3c-chrome-tests")
    /**
     * @DisplayName is a JUnit 5 annotation that defines test case name.
    For more information visit the docs: https://junit.org/junit5/docs/5.0.2/api/org/junit/jupiter/api/DisplayName.html

     */
    @DisplayName("Junit5W3CChromeTest()")
    /**
     * @Test is a JUnit 5 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"
    - Use and If/Else block to determine String match
    For more information visit the docs: https://junit.org/junit5/docs/5.0.2/api/org/junit/jupiter/api/Test.html
     */
    @Test
    public void JUnit5w3cChromeTest() throws AssertionError {
        driver.navigate().to("https://www.saucedemo.com");
        String getTitle = driver.getTitle();
        Assertions.assertEquals(getTitle, "Swag Labs");
        if (getTitle.equals("Swag Labs")) {
            result = true;
        }else result = false;
    }
    /**
     * @AfterEach is a JUnit 5 annotation that defines any postrequisite test method tasks .
    In the example below we:
    - Use the JavascriptExecutor class to send our test results 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: https://junit.org/junit5/docs/5.0.2/api/org/junit/jupiter/api/AfterEach.html
     */
    @AfterEach
    public void teardown() {
        ((JavascriptExecutor) driver).executeScript("sauce:job-result=" + (result ? "passed" : "failed"));
        driver.quit();
    }
}

JUnit Jupiter Example Walkthrough

  1. Download or clone the script from this GitHub repository.

  2. Ensure you have the prerequisite software.

  3. Resolve any dependencies:

    $ mvn dependency:resolve
  4. Export your Sauce Labs Username and Access Key:

    Sauce Labs Username and Access Key Example:
    export SAUCE_USERNAME=my-sauce-username
    export SAUCE_ACCESS_KEY=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxxx
  5. Run the following command:

    $ mvn clean test -Dtest=JUnit5W3CChromeTest
 Click here to see the full example

Pytest W3C Chrome 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": "61.0",
        "seleniumVersion": "3.11.0",
        'name': 'Pytest Chrome W3C Sample'
    }

    chromeOpts =  {
        'platformName':"Windows 10",
        'browserName': "chrome",
        'browserVersion': '61.0',
        'goog:chromeOptions': {'w3c': True},
        'sauce:options': sauceOptions
    }

    browser = webdriver.Remote(remote_url, desired_capabilities=chromeOpts)
    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

PyTest Example Walkthrough

  1. Download or clone the script from this GitHub repository.
  2. Ensure you have the prerequisite software.
  3. Resolve any dependencies:

    $ pip install -r w3c-examples/requirements.txt
  4. Export your Sauce Labs Username and Access Key:

    Sauce Labs Username and Access Key Example:
    export SAUCE_USERNAME=my-sauce-username
    export SAUCE_ACCESS_KEY=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx2cy8f4
  5. Run the following command:

    $ pytest w3c-examples/pytest/*.py
 Click here to see the full example

Unittest W3C Chrome Example
import unittest
import os
from selenium import webdriver


class TestW3COptions(unittest.TestCase):

    def setUp(self):
        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": "61.0",
            "seleniumVersion": "3.11.0",
            'name': 'Unittest Chrome W3C Sample'
        }

        chromeOpts =  {
            'platformName':"Windows 10",
            'browserName': "chrome",
            'browserVersion': '61.0',
            'goog:chromeOptions': {'w3c': True},
            'sauce:options': sauceOptions
        }

        self.driver = webdriver.Remote(remote_url, desired_capabilities=chromeOpts)

    def tearDown(self):
        #driver.execute_script('sauce:job-result={}'.format(report.outcome))
        self.driver.quit()

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

unittest Example Walkthrough

  1. Download or clone the script from our GitHub repository
  2. Ensure you have the prerequisite software
  3. Install any dependencies:

    $ pip install -r w3c-examples/requirements.txt
  4. Export your Sauce Labs Username and Access Key:

    Sauce Labs Username and Access Key Example:
    export SAUCE_USERNAME=my-sauce-username
    export SAUCE_ACCESS_KEY=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx2cy8f4
  5. Run the following commands:

    $ python -m unittest w3c-examples/unittest/*.py
 Click here to see the full example.

async-await-test.js
const {By, promise} = require('selenium-webdriver');
let expect = require('chai').expect;
let webdriver = require('selenium-webdriver');

promise.USE_PROMISE_MANAGER = false;

let username = process.env.SAUCE_USERNAME,
    accessKey = process.env.SAUCE_ACCESS_KEY,
    /* Change the baseURL to your application URL */
    baseUrl = "https://www.saucedemo.com",
    tags = ["sauceDemo", "async", "node", "webdriverjs" ],
    driver;

    describe ('W3C async/await tests', function() {
    this.timeout(40000);
    beforeEach(async function () {
        driver = await new webdriver.Builder().withCapabilities({
            'browserName': 'chrome',
            'platformName': 'Windows 10',
            'browserVersion': 'latest',
            'goog:chromeOptions' : { 'w3c' : true },
            'sauce:options': {
                'username': username,
                'accessKey': accessKey,
                'seleniumVersion': '3.141.59',
                'build': 'js-w3c-examples',
                'name': 'js-w3c: ' + this.currentTest.title,
                'maxDuration': 3600,
                'idleTimeout': 1000,
                'tags': tags
            }}).usingServer("https://ondemand.saucelabs.com/wd/hub")
            .build();
        await driver.getSession().then(function (sessionid) {
            driver.sessionID = sessionid.id_;
        });
    });

    afterEach(async function() {
        await driver.executeScript("sauce:job-result=" + (this.currentTest.state));
        await driver.quit();
    });

    it('get-title-test', async function() {
        await driver.get(baseUrl);
        const title = await driver.getTitle();
        console.log('Page Title is: ' + title);
        expect(title).equals('Swag Labs');
    });

    it('login-test', async function() {
        await driver.get(baseUrl);
        await driver.findElement(By.id('user-name')).sendKeys('standard_user');
        await driver.findElement(By.id('password')).sendKeys('secret_sauce');
        await driver.findElement(By.className('btn_action')).click();
        const currentURL = await driver.getCurrentUrl();
        console.log('URL is:  ' + currentURL);
        expect(currentURL).equals('https://www.saucedemo.com/inventory.html');
    });
});

Mocha-Chai Example Walkthrough

  1. Download or clone the script from this GitHub repository.

  2. Ensure you have the prerequisite software.

  3. Ins$tall node package dependencies:

    $ npm --prefix ./w3c-example install ./w3c-example
  4. Export your Sauce Labs Username and Access Key:

    Sauce Labs Username and Access Key Example:
    export SAUCE_USERNAME=my-sauce-username
    export SAUCE_ACCESS_KEY=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx2cy8f4
  5. Run the following command:

    $ npm --prefix ./w3c-example test

    You should see the following output (or something similar) in the console:

     mocha "test/async-await-test.js"
    
    
    
      headless chrome test
    Page Title is: Swag Labs
        ✓ get-title-test (2594ms)
    
    
      1 passing (13s)                                                              
 Click here to see the full example.

chrome_example_spec.rb
    # The 'require' definitions define which gems dependencies our script needs. In this example we have
    # - The selenium-webdriver gem
    # - The rspec framework gem
    # - The sauce_whisk gem (a wrapper for the SauceLabs REST API)

require "selenium-webdriver"
require "rspec"
require "sauce_whisk"

    # The basic structure of RSpec uses 'describe' and 'it' to format our script in a conversational tone.
    # 'describe' represents the highest context, for example if we were testing authentication features it would say something like: '.authentication', and the 'it' would say something like 'should login'

describe "W3C RSpec Test" do

    # before is an RSpec method that allows us to define prerequisite test execution steps such as:
    #     - defining the browser name
    #     - defining the browser version
    #     - defining the OS version and platform
    #     - defining the sauce:options capabilities, in this case the test name, the SauceLabs credentials, and the selenium version

  before(:each) do |test|
    caps = {
        browser_name: 'chrome',
        # platform_version now becomes platform_name with the W3C bridge.
        # For more details see: https://www.rubydoc.info/gems/selenium-webdriver/Selenium/WebDriver/Remote/W3C/Capabilities
        platform_name: 'windows 10',
        browser_version: '61.0',
        # w3c is note enabled by default in Chrome (in Chrome < 75), set the w3c setting to true
        "goog:chromeOptions" => {w3c: true},
        # use sauce:options to handle all saucelabs.com-specific capabilities such as:
        # username, accesskey, build number, test name, timeouts etc.
        "sauce:options" => {
            name: test.full_description,
            selenium_version: '3.141.59',
            build: 'w3c-ruby-tests-1.0.0',
            username: ENV['SAUCE_USERNAME'],
            access_key: ENV['SAUCE_ACCESS_KEY']
        }
    }
    @driver = Selenium::WebDriver.for(:remote,
                                     url: 'https://ondemand.saucelabs.com:443/wd/hub',
                                     desired_capabilities: caps)
  end

    # Again, 'it' represents the business-level logic that we're testing,
    # in this case we're checking to see if our test in SauceLabs session can open Chrome using W3C, then check the title page.

  it "should_open_chrome" do
    @driver.get('https://www.saucedemo.com')
    puts "title of webpage is: #{@driver.title}"
  end

    # Here we use 'after' which is another RSpec method that handles all postrequisite test execution steps such as:
    #     - sending the results to SauceLabs.com
    #     - Tearing down the current RemoteWebDriver session so that the test VM doesn't hang

  after(:each) do |example|
    # SauceWhisk::Jobs is a Ruby wrapper for the SauceLabs REST API. Here we're updating the job method
    # For more info please visit the Sauce Labs REST API Documentation: https://wiki.saucelabs.com/display/DOCS/Job+Methods
    SauceWhisk::Jobs.change_status(@driver.session_id, !example.exception)
    @driver.quit
  end
end

Rspec Example Walkthrough

  1. Download or clone the script from this GitHub repository.

  2. Ensure you have the prerequisite software.

  3. Install gemfile/package dependencies:

    $ gem install bundler
    $ bundle init
    $ bundle install --path .bundle
  4. Export your Sauce Labs Username and Access Key:

    Sauce Labs Username and Access Key Example:
    export SAUCE_USERNAME=my-sauce-username
    export SAUCE_ACCESS_KEY=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx2cy8f4
  5. Run the following command:

    $ bundle exec rspec
 Click here to expand...

NUniteExamples.cs
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();
        }
    }
}

NUnit Example Walkthrough

  1. Download or clone the script from this GitHub repository.
  2. Ensure you have the prerequisite software.
  3. In Visual Studio, open the solution.
  4. Export your Sauce Labs Username and Access Key:

    export SAUCE_USERNAME=my-sauce-username
    export SAUCE_ACCESS_KEY=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx2cy8f4
  5. In Visual Studio Test Explorer, run tests in Selenium3.Nunit.Scripts.SimpleExamples.W3CExamplesOnSelenium3.cs.

Common Test Script Configuration Errors to Avoid

Here are some things to keep in mind when configuring your test script capabilities.

Don't Mix W3C Capabilities with JWP Capabilities

It's important not to mix W3C WebDriver-compliant capabilities with legacy JWP capabilities. This will result in a system error when you're spinning up a WebDriver session:

Mixed Capabilities Error
selenium.common.exceptions.WebDriverException: Message: Misconfigured -- Mixed Capabilities Error.

W3C keys (platformName/browserVersion) were detected alongside JWP keys (platform/version). To fix this, replace all JWP keys with W3C keys.

The following desired capabilities were received:
{'browserName': 'chrome',
 'browserVersion': '80',
 'platform': 'Windows'} 

See https://wiki.saucelabs.com/display/docs/w3c+capabilities+support for more details.


To fix this particular error, you'd need to change platform to platformName and then change version to browserVersion:

Solution
browserName: 'chrome',
platformName: 'Windows',
browserVersion: '80'
sauce:options: {
  name: 'My test name',
  build: 'My build',
  username: "SAUCE_USERNAME",
  accessKey: "SAUCE_ACCESS_KEY"
  seleniumVersion: "3.141.59"
} 

Additional Resources