Getting Started with GitHub Actions, WebDriverIO and Sauce Labs

Getting Started with GitHub Actions, WebDriverIO and Sauce Labs

In this article, we will discuss how to install and run WebDriverIO locally and in the cloud using GitHub Actions and Sauce Labs.


What is WebDriverIO?

No alt text provided for this image

WebDriverIO is the popular library for developing Selenium WebDriver test scenarios using Node.JS.

It is written in JavaScript, runs on Node, and provides a powerful framework for both mobile and web automation.

Easy setup through test runner client.

It implements all Webdriver protocol commands and provides useful integrations with other tools.

It provides support for your favorite BDD/TDD test framework and will run your tests locally or in the cloud using Sauce Labs, BrowserStack or TestingBot.

You can know more about WebDriverIO from this link

GitHub Actions

No alt text provided for this image


GitHub Actions make it easy to automate all your software workflows, now with world-class CI/CD. Build, test, and deploy your code right from GitHub. Make code reviews, branch management, and issue triaging work the way you want.

Run a workflow on any GitHub event

Kick-off workflows with GitHub events like push, issue creation, or a new release. Combine and configure actions for the services you use, built and maintained by the community.

You can know more about the features from this link


What is SauceLabs?

The world's largest continuous testing cloud of web and mobile applications. Access web browsers, mobile emulators, simulators, and real mobile devices.

No alt text provided for this image

SauceLabs Products and Services

SauceLabs Continuous Testing Cloud enables development and quality teams to test up to 10x faster. SauceLabs provides the comprehensive coverage, scalability, and analytics required to rapidly deliver a flawless user experience.

No alt text provided for this image
No alt text provided for this image


Create Sauce Labs Free (Trial) Account

You can create your trial account from this link:

https://saucelabs.com/sign-up

The Free trial account includes:

Start testing today on thousands of browser/OS platform combinations, EMU/SIM and real Android and iOS devices.

  • Instant access to 900+ desktop browser & OS combos
  • Instant access to 200+ mobile emulators & simulators100 minutes of automated testing
  • Instant access to real mobile devices
  • 1 session on the Real Device Cloud
  • 2 concurrent sessions on the Virtual Device Cloud
  • 100 minutes of automated testing


First Part - WebDriverIO + GitHub Actions + Headless Chrome

In the following steps, we will know how to set up our Github Actions workflow and run our WebdriverIO tests with Chrome browser in a headless mode:

Install and run WebDriverIO in your machine:

The better way to install WebDriverIO step by step that you can follow the steps in the link

https://webdriver.io/docs/gettingstarted.html

After the installation steps, you will have the following script basic.js

const assert = require('assert')

describe('webdriver.io page', () => {
    it('should have the right title', () => {
        browser.url('https://webdriver.io')
        const title = browser.getTitle()
        assert.strictEqual(title, 'WebdriverIO · Next-gen WebDriver test framework for Node.js')
    })
})

And you can run it locally on Chrome Browser using the following command:

./node_modules/.bin/wdio wdio.conf.js

To be able to run it in a Headless mode you can update the following capabilities section in wdio.conf.js file like this:

capabilities: [{
    maxInstances: 5,
    browserName: 'chrome',
        'goog:chromeOptions': {
         args: ['headless', 'disable-gpu'],
         },
}],

You will notice that the Chrome browser is running in a headless mode during the test.

Now our project is ready to push to GitHub repository to be able to integrate it with GitHub Actions with the following steps:

1- Create a new GitHub repository and commit our code from the article to GitHub Repository

No alt text provided for this image

2- Click on the Actions tab

No alt text provided for this image


3- Click on Set up Node.js Workflow

No alt text provided for this image

4- The Editor will open with the .yml file and you can change the name or leave it as default

No alt text provided for this image

5- We will replace the content of the file with the following structure:

name: Node CI


on: [push]


jobs:
  build:


    runs-on: ubuntu-latest


    strategy:
      matrix:
        node-version: [8.x, 10.x, 12.x]


    steps:
    - uses: nanasess/setup-chromedriver@master
      with:
       chromedriver-version: '77.0.3865.40'
    - run: |
       export DISPLAY=:99
       chromedriver --url-base=/wd/hub &
       sudo Xvfb -ac :99 -screen 0 1280x1024x24 > /dev/null 2>&1 & # optional
    
    - uses: actions/checkout@v1
    - name: Use Node.js ${{ matrix.node-version }}
      uses: actions/setup-node@v1
      with:
        node-version: ${{ matrix.node-version }}
    - name: npm install, build, and test
      run: |
        npm ci
        npm run build --if-present
        ./node_modules/.bin/wdio wdio.conf.js
      env:
        CI: true

The above code is using this action to be able to install a Chrome browser, also we are running our script on the Ubuntu machine with different NodeJS.

7- We need to commit the file with a new branch to run the action on the Pull Request

No alt text provided for this image

8- Click on Create Pull Request to trigger the workflow

No alt text provided for this image

9- And the Action/Workflow will start running

No alt text provided for this image

10 - Click on Details to view the live log console and you will notice that webdriverIO installed and run your test in a headless mode.

11- You will notice that you have a new folder in your project with the workflow YAML file and you can pull it locally and change it as you want.

If we change in the file or add any new commit to the project the workflow will be triggered automatically.

No alt text provided for this image


Second Part - WebDriverIO + GitHub Actions + Sauce Labs

In the following steps, we will know how to set up our Github Actions workflow and run our WebdriverIO tests with Sauce Labs browsers:

We need to add your Sauce Labs username and access key to GitHub secret by the following step:

RECOMMENDED: You can try it with a private repository because maybe your secrets can be visible to the others.

1- Click on the Setting tab and select Secrets

No alt text provided for this image

2- Add your Sauce username and access key as a secret (key and value)

No alt text provided for this image
No alt text provided for this image
No alt text provided for this image

3- We need to add these env variables in our wdio.conf.js and in our Github workflow like the following:

The new and final wdio.conf.js:

exports.config = {
    //
    // ====================
    // Runner Configuration
    // ====================
    //
    // WebdriverIO allows it to run your tests in arbitrary locations (e.g. locally or
    // on a remote machine).
    runner: 'local',
    //
    // =================
    // Service Providers
    // =================
    // WebdriverIO supports Sauce Labs, Browserstack, and Testing Bot (other cloud providers
    // should work too though). These services define specific user and key (or access key)
    // values you need to put in here in order to connect to these services.
    //
    user: process.env.SAUCE_USERNAME,
    key: process.env.SAUCE_ACCESS_KEY,
    //
    // If you run your tests on SauceLabs you can specify the region you want to run your tests
    // in via the `region` property. Available short handles for regions are `us` (default) and `eu`.
    // These regions are used for the Sauce Labs VM cloud and the Sauce Labs Real Device Cloud.
    // If you don't provide the region it will default for the `us`


    //
    // ==================
    // Specify Test Files
    // ==================
    // Define which test specs should run. The pattern is relative to the directory
    // from which `wdio` was called. Notice that, if you are calling `wdio` from an
    // NPM script (see https://docs.npmjs.com/cli/run-script) then the current working
    // directory is where your package.json resides, so `wdio` will be called from there.
    //
    specs: [
        'test/specs/*js'
    ],
    // Patterns to exclude.
    exclude: [
        // 'path/to/excluded/files'
    ],
    //
    // ============
    // Capabilities
    // ============
    // Define your capabilities here. WebdriverIO can run multiple capabilities at the same
    // time. Depending on the number of capabilities, WebdriverIO launches several test
    // sessions. Within your capabilities you can overwrite the spec and exclude options in
    // order to group specific specs to a specific capability.
    //
    // First, you can define how many instances should be started at the same time. Let's
    // say you have 3 different capabilities (Chrome, Firefox, and Safari) and you have
    // set maxInstances to 1; wdio will spawn 3 processes. Therefore, if you have 10 spec
    // files and you set maxInstances to 10, all spec files will get tested at the same time
    // and 30 processes will get spawned. The property handles how many capabilities
    // from the same test should run tests.
    //
    maxInstances: 40,
    //
    // If you have trouble getting all important capabilities together, check out the
    // Sauce Labs platform configurator - a great tool to configure your capabilities:
    // https://docs.saucelabs.com/reference/platforms-configurator
    //
    capabilities: [
        // maxInstances can get overwritten per capability. So if you have an in-house Selenium
        // grid with only 5 firefox instance available you can make sure that not more than
        // 5 instance gets started at a time.
        //maxInstances: 5,
        //
      {browserName: 'firefox', platformName: 'Windows 10', browserVersion: 'latest', 'sauce:options': {'seleniumVersion': '3.14.0'}},
      {browserName: 'chrome', platform: 'OS X 10.13', version: 'latest'},
      {browserName: 'internet explorer', platform: 'Windows 10', version: '11.0'}
    ],
    //
    // ===================
    // Test Configurations
    // ===================
    // Define all options that are relevant for the WebdriverIO instance here
    //
    // Level of logging verbosity: trace | debug | info | warn | error | silent
    logLevel: 'silent',
    //
    // Set specific log levels per logger
    // loggers:
    // - webdriver, webdriverio
    // - wdio-applitools-service, wdio-browserstack-service, wdio-devtools-service, wdio-sauce-service
    // - wdio-mocha-framework, wdio-jasmine-framework
    // - wdio-local-runner, wdio-lambda-runner
    // - wdio-sumologic-reporter
    // - wdio-cli, wdio-config, wdio-sync, wdio-utils
    // Level of logging verbosity: trace | debug | info | warn | error | silent
    // logLevels: {
        // webdriver: 'info',
        // 'wdio-applitools-service': 'info'
    // },
    //
    // If you only want to run your tests until a specific amount of tests have failed use
    // bail (default is 0 - don't bail, run all tests).
    bail: 0,
    //
    // Set a base URL in order to shorten url command calls. If your `url` parameter starts
    // with `/`, the base url gets prepended, not including the path portion of your baseUrl.
    // If your `url` parameter starts without a scheme or `/` (like `some/path`), the base url
    // gets prepended directly.
    baseUrl: 'https://webdriver.io',
    //
    // Default timeout for all waitFor* commands.
    waitforTimeout: 10000,
    //
    // Default timeout in milliseconds for request
    // if Selenium Grid doesn't send response
    connectionRetryTimeout: 90000,
    //
    // Default request retries count
    connectionRetryCount: 3,
    //
    // Test runner services
    // Services take over a specific job you don't want to take care of. They enhance
    // your test setup with almost no effort. Unlike plugins, they don't add new
    // commands. Instead, they hook themselves up into the test process.
    services: ['sauce'],
    //
    // Framework you want to run your specs with.
    // The following are supported: Mocha, Jasmine, and Cucumber
    // see also: https://webdriver.io/docs/frameworks.html
    //
    // Make sure you have the wdio adapter package for the specific framework installed
    // before running any tests.
    framework: 'mocha',
    //
    // The number of times to retry the entire specfile when it fails as a whole
    // specFileRetries: 1,
    //
    // Test reporter for stdout.
    // The only one supported by default is 'dot'
    // see also: https://webdriver.io/docs/dot-reporter.html
    reporters: ['spec'],

    //
    // Options to be passed to Mocha.
    // See the full list at https://mochajs.org/
    mochaOpts: {
        timeout: 60000
    },
    //
    // =====
    // Hooks
    // =====
    // WebdriverIO provides several hooks you can use to interfere with the test process in order to enhance
    // it and to build services around it. You can either apply a single function or an array of
    // methods to it. If one of them returns with a promise, WebdriverIO will wait until that promise got
    // resolved to continue.
    /**
     * Gets executed once before all workers get launched.
     * @param {Object} config wdio configuration object
     * @param {Array.<Object>} capabilities list of capabilities details
     */
    // onPrepare: function (config, capabilities) {
    // },
    /**
     * Gets executed just before initialising the webdriver session and test framework. It allows you
     * to manipulate configurations depending on the capability or spec.
     * @param {Object} config wdio configuration object
     * @param {Array.<Object>} capabilities list of capabilities details
     * @param {Array.<String>} specs List of spec file paths that are to be run
     */
    // beforeSession: function (config, capabilities, specs) {
    // },
    /**
     * Gets executed before test execution begins. At this point you can access to all global
     * variables like `browser`. It is the perfect place to define custom commands.
     * @param {Array.<Object>} capabilities list of capabilities details
     * @param {Array.<String>} specs List of spec file paths that are to be run
     */
    // before: function (capabilities, specs) {
    // },
    /**
     * Runs before a WebdriverIO command gets executed.
     * @param {String} commandName hook command name
     * @param {Array} args arguments that command would receive
     */
    // beforeCommand: function (commandName, args) {
    // },

    /**
     * Hook that gets executed before the suite starts
     * @param {Object} suite suite details
     */
    // beforeSuite: function (suite) {
    // },
    /**
     * Function to be executed before a test (in Mocha/Jasmine) or a step (in Cucumber) starts.
     * @param {Object} test test details
     */
    // beforeTest: function (test) {
    // },
    /**
     * Hook that gets executed _before_ a hook within the suite starts (e.g. runs before calling
     * beforeEach in Mocha)
     */
    // beforeHook: function () {
    // },
    /**
     * Hook that gets executed _after_ a hook within the suite starts (e.g. runs after calling
     * afterEach in Mocha)
     */
    // afterHook: function () {
    // },
    /**
     * Function to be executed after a test (in Mocha/Jasmine) or a step (in Cucumber) starts.
     * @param {Object} test test details
     */
    // afterTest: function (test) {
    // },
    /**
     * Hook that gets executed after the suite has ended
     * @param {Object} suite suite details
     */
    // afterSuite: function (suite) {
    // },

    /**
     * Runs after a WebdriverIO command gets executed
     * @param {String} commandName hook command name
     * @param {Array} args arguments that command would receive
     * @param {Number} result 0 - command success, 1 - command error
     * @param {Object} error error object if any
     */
    // afterCommand: function (commandName, args, result, error) {
    // },
    /**
     * Gets executed after all tests are done. You still have access to all global variables from
     * the test.
     * @param {Number} result 0 - test pass, 1 - test fail
     * @param {Array.<Object>} capabilities list of capabilities details
     * @param {Array.<String>} specs List of spec file paths that ran
     */
    // after: function (result, capabilities, specs) {
    // },
    /**
     * Gets executed right after terminating the webdriver session.
     * @param {Object} config wdio configuration object
     * @param {Array.<Object>} capabilities list of capabilities details
     * @param {Array.<String>} specs List of spec file paths that ran
     */
    // afterSession: function (config, capabilities, specs) {
    // },
    /**
     * Gets executed after all workers got shut down and the process is about to exit.
     * @param {Object} exitCode 0 - success, 1 - fail
     * @param {Object} config wdio configuration object
     * @param {Array.<Object>} capabilities list of capabilities details
     * @param {<Object>} results object containing test results
     */
    // onComplete: function(exitCode, config, capabilities, results) {
    // },
    /**
    * Gets executed when a refresh happens.
    * @param {String} oldSessionId session ID of the old session
    * @param {String} newSessionId session ID of the new session
    */
    //onReload: function(oldSessionId, newSessionId) {
    //}
}

We will notice that we add sauce labs ENV variables like

user: process.env.SAUCE_USERNAME,
key: process.env.SAUCE_ACCESS_KEY,

And change the capabilities to run on different OS and Browsers on Sauce Labs be like this:

capabilities: [
    // maxInstances can get overwritten per capability. So if you have an in-house Selenium
    // grid with only 5 firefox instance available you can make sure that not more than
    // 5 instance gets started at a time.
    //maxInstances: 5,
    //
  {browserName: 'firefox', platformName: 'Windows 10', browserVersion: 'latest', 'sauce:options': {'seleniumVersion': '3.14.0'}},
  {browserName: 'chrome', platform: 'OS X 10.13', version: 'latest'},
  {browserName: 'internet explorer', platform: 'Windows 10', version: '11.0'}
],

And the service becomes sauce:

services: ['sauce'],

for more info about Sauce Labs integration and WebDriverIO, you can check this link

4- We need to add the Github ENV or the Secrets to our Workflow to be like:

name: Node CI

on: [push]

jobs:
  build:

    runs-on: ubuntu-latest

    strategy:
      matrix:
        node-version: [8.x, 10.x, 12.x]

    steps:
      - uses: actions/checkout@v1
      - name: Use Node.js ${{ matrix.node-version }}
        uses: actions/setup-node@v1
        with:
          node-version: ${{ matrix.node-version }}
      - name: npm install, build, and test
        env:
          SAUCE_USERNAME: ${{ secrets.SAUCE_USERNAME }}
          SAUCE_ACCESS_KEY: ${{ secrets.SAUCE_ACCESS_KEY }}
        run: |
          npm ci
          npm run build --if-present
          ./node_modules/.bin/wdio wdio.conf.js

5- Commit the changes and you will notice that your tests running on Sauce Labs and it gives you the links for the runners.

No alt text provided for this image
No alt text provided for this image
No alt text provided for this image


With GitHub Actions and Sauce Labs, you can set up your CI pipeline and running your tests in parallel with a few steps.



Thank you for reading

Happy Testing

Moataz

Stefan Franzén

Engineering Management of scale up companies | Builds top efficient organisations by setting people up for success

5 年

Been curious to check out github actions myself, thanks for sharing

要查看或添加评论,请登录

Moataz Nabil的更多文章

社区洞察

其他会员也浏览了