Part 3. Framework Structure & Configuration

Framework Structure

Introduction

In this section, we will begin to add our folders and files that our framework will need. We will also add a .gitignore file so that if you decide to put your framework in a Git repository, you are able to without unnecessary files being included in the repository.

Adding a .gitignore file

  1. Open up a terminal (or command prompt) and change directory (cd) in to your project root…
    cd your/project/root

     (change ‘your/project/root’ to the path of your local project’s root)

  2. First, let’s initialise an empty git repository…
    git init
  3. Next, create (touch) a .gitignore file…
    touch .gitignore
  4. Next, go into the nano editor for the .gitignore file we just created…
    nano .gitignore
  5. Add the following lines in your .gitignore file to ignore the packages in our ‘/node_modules’ folder as well as any folders specific to our code editor (e.g. ‘.vscode/’) and the folder where we keep screenshots of errors (this doesn’t need to be in the git repository either)…
    node_modules/
    .vscode/
    errorShots/

    You’re now ready to setup your own GitHub/GitLab repo, if you desire to do so (I won’t be covering that in this blog series).

Directory Structure

  1. Open up a terminal (or command prompt) and change directory (cd) in to your project root…
    cd your/project/root

     (change ‘your/project/root’ to the path of your local project’s root)

  2. First, let’s make a ‘src’ directory (mkdir) that will contain our features folder…
    mkdir src
  3. Next, let’s make the ‘resources’ directory within the ‘src’ directory
    mkdir src/resources
  4. Next, let’s make the ‘features’ sub-directory in the ‘resources’ folder, that will hold all of our Cucumber feature files…
    mkdir src/resources/features
  5. Next, make a ‘test’ sub-directory in the ‘src’ directory…
    mkdir src/test
  6. The rest of the directories we will make will be sub-directories inside the ‘/src/test’ directory, so let’s change directory into the ‘src/test’ folder we just made…
    cd src/test
  7. Next, let’s make the ‘steps’ folder that will hold all our step definitions (the glue between our Gherkin feature files and our javascript test code)…
    mkdir steps
  8. Next, let’s make the ‘page-objects’ folder, that will contain both our pages and their appropriate page objects…
    mkdir page-objects

Initial Files in each Directory

Features Folder

  1. Change directory from ‘src/test’ to the ‘/resources/features’ folder…
    cd ../resources/features
  2. Next, create (touch) the file ‘base-scenarios.feature’ in the ‘/resources/features’ folder…
    touch base-scenarios.feature

Steps Folder

  1. Change directory back from ‘/resources/features/’ to the ‘src/test’ folder…
    cd ../../test
  2. Next, create (touch) the following step definition files in the ‘/src/test/steps’ folder (the ‘steps’ folder will contain all our step definitions, which acts as the glue that connects our BDD/Gherkin language scenarios in our Feature files, to our test javascript functions.  Please see https://docs.cucumber.io/cucumber/step-definitions/ for more information)…
    touch steps/base-scenarios-steps.js

     (this file contains all the step definitions for your base scenarios)

    touch steps/dynamic-table-steps.js

     (this file contains all the step definitions for scenario lines which use dynamic data tables)

    touch steps/non-dynamic-table-steps.js

      (this file contains all the step definitions for scenario lines which use non-dynamic data tables)

    touch steps/click-steps.js

     (this file contains all the step definitions for scenario lines which perform a click action)

    touch steps/send-keys-steps.js

     (this file contains all the step definitions for scenario lines which sends keys to a web element)

    touch steps/validation-steps.js

     (this file contains all the step definitions for our test assertions)

PageObjects Folder

  1. In the same terminal (or command prompt) window (you should still be in the ‘/src/test’ directory), create (touch) the following file for the base page object, which will contain all our generic selectors and functions and which all other page objects will extend from (the ‘page-objects’ folder will contain all files for our page objects, following Page Object Model principles. Please see http://webdriver.io/guide/testrunner/pageobjects.html for more information)…
    touch page-objects/base.page.js

Tweaking the WDIO Configuration

Launching Visual Studio Code

  1. In the same terminal (or command prompt) window (you should currently be in the ‘/src/test’ directory), change directory (cd) to your project’s root…
    cd ../..

     (‘..’ means back one folder)

  2.  Now let’s launch Visual Studio Code from our command line…
    code .

Editing the package.json file

Let’s quickly edit our package.json file, adding a description as well as a ‘test’ script

  1. Open up the package.json file
  2. Edit the value for the “test” key in ‘scripts’ to read “wdio”…
    "scripts": {
        "test": "wdio"
      },
  3. Edit the description to read something suitable…
    "description": "WebDriverIO Cucumber Framework Tutorial",
  4. Add the following Babel presets at the bottom of the file, before the last closing bracket…
    "babel": {
      "presets": [
        [
          "@babel/env",
          {
            "targets": {
              "node": "current"
            }
          }
        ]
      ]
    }

    The whole thing should look similar to below…

    {
      "name": "webdriverio-framework",
      "version": "1.0.0",
      "description": "WebDriverIO Cucumber Framework Tutorial",
      "main": "index.js",
      "scripts": {
        "test": "wdio"
      },
      "keywords": [],
      "author": "",
      "license": "ISC",
      "devDependencies": {
        "@babel/core": "^7.1.6",
        "@babel/preset-env": "^7.1.6",
        "@babel/register": "^7.0.0",
        "wdio-cucumber-framework": "^2.2.8",
        "wdio-cucumber-snippet-reporter": "0.0.5",
        "wdio-selenium-standalone-service": "0.0.11",
        "wdio-spec-reporter": "^0.1.5",
        "webdriverio": "^4.14.0"
      },
      "dependencies": {
        "chai": "^4.2.0",
        "glob": "^7.1.3"
      },
      "babel": {
        "presets": [
          [
            "@babel/env",
            {
              "targets": {
                "node": "current"
              }
            }
          ]
        ]
      }
    }

Editing the wdio.conf.js file

Debug timeout

Let’s add a debug timeout at the top of our config file so that when we use the browser.debug() command when debugging our tests, it doesn’t timeout too quickly.

  1. Add the following line to the very top of the ‘wdio.conf.js’ file…
    let timeout = process.env.DEBUG ? 999999 : 30000;
  2. Go to around line 143 in the ‘wdio.conf.js’ file and edit the timeout value in the Cucumber Options to call the variable we just created…
    timeout: timeout,     // <number> timeout for step definitions

Exclude our Page Objects from the Test Runner

When running our tests, we want to make sure the WDIO Test Runner excludes our page objects, let’s uncomment this section in our config file and add the exclusion now.

  1. In the ‘exclude’ section near the top, uncomment the file path and change it to match below (we use a glob pattern to exclude any files with .page.js in it within any subdirectory of ‘/src/test’)…
    // Patterns to exclude.
    exclude: [
        './src/test/**/*.page.js'
    ],

Change the browser we run the tests in

By default, WDIO Test Runner is set to run tests in Firefox, you can either leave this as is or change it Chrome if you want.  For the purposes of this blog, we will be running our tests in Chrome. You could also add multiple browsers in the ‘capabilities’ array and even use a selenium grid, however I won’t be covering that in this blog series.

  1. Change the value of ‘browserName’ on around line 49 to ‘chrome’…
    browserName: 'chrome'

Start the Selenium-Standalone service automatically

In our WDIO Test Runner config file, we are able to specify any services that we want to run at the start by default. Let’s specify that we want to run the selenium-standalone service 🙂

  1. Uncomment the ‘services:’ around line 116 and call ‘selenium-standalone’ in the array value…
    services: ['selenium-standalone'],

Adding in our Reporters

In our WDIO Test Runner config file, we are able to specify an array of reporters we want to use. Let’s do this now to specify the Spec reporter we chose when setting up WDIO and also the wdio-cucumber-snippet-reporter, so we can see pending/undefined step definitions in the console when we try to run our test scenarios.

  1. Uncomment the ‘reporters:’ around line 128 and edit the array value to read like below…
    reporters: ['spec', 'cucumber-snippet'],

Editing the Cucumber Options

Let’s now edit some of the values for our Cucumber options, such as the compiler we use etc.

  1. Edit the ‘require:’ value around line 131 to require the glob package we installed earlier…
    require: require('glob').sync('./src/test/steps/**/*.js'),
  2. Edit the ‘compiler’ array value around line 133 to use ‘js:@babel/register’, like below…
    compiler: [
      'js:@babel/register',
    ],
  3. Also edit the ‘snippets’ boolean value around line 140 to equal false, like below…
    snippets: false,     // <boolean> hide step definition snippets for pending steps
    
  4. Next, edit the ‘ignoreUndefinedDefinitions’ boolean value around line 146 to equal true (necessary for wdio-cucumber-snippet-reporter), like below…
    ignoreUndefinedDefinitions: true, // <boolean> Enable this config to treat undefined definitions as warnings.

Editing the Hooks

before:

Let’s require our Chai assertion library before a test run. This way we don’t have to require/import it in any of our step definition files 🙂

  1. Uncomment the ‘before’ around lines 179-181 and add the following…
    before: function (capabilities, specs) {
        should = require('chai').should;
        expect = require('chai').expect;
        assert = require('chai').assert;
    },

Creating the Base Page Object

base.page.js

First of all, we need to create our generic page object for ‘page’ with an empty constructor, that all other page objects will inherit from.

  1. Open up the ‘base.page.js’ file in the ‘/page-objects’ folder and edit it to match below…
    export default class Page {
      constructor() {}
    
      open (path) {
        browser.url(path)
      }
    }
    

Congratulations, our WDIO Test Runner should now be configured correctly. In the next section we will begin to add our base scenarios 😀