4

http://webdriver.io/guide/getstarted/modes.html

I'm going absolutely nuts trying to debug a webdriverio test using Chromedriver. You simply cannot step through the code because webdriverio commands are asynchronous and the browser session is out of sync with the test.

This is frustrating because reading the docs, it seems you need a testing framework like Chai or wdio to generate tests, but this seems like a lot of work just to have procedural synchronous commands.

I just need to crawl some websites using webdriverio but this asynchronous commands are far too difficult to debug using Chrome devtools.

Is there any way to force webdriverio to behave synchronously?

ex)

var loadedPage = webdriverio.remote(options).init().url('https://google.com');

except loadedPage is not ready and is undefined by the time debug moves to next line.

Erik B
  • 35,941
  • 21
  • 106
  • 122
I Love Python
  • 784
  • 1
  • 11
  • 20

1 Answers1

5

Well, WebdriverIO is just a jewel of an automation framework and the comprehensive documentation is one of its strong suits. As you correctly pointed out, everything is asynchronous, but with WDIO you also have the option to go full-synchronous if you come from a traditional sequential programming background.

First off, you will have to read-up a bit about JavaScript Promises, especially the .then() function.

var webdriverio = require('webdriverio');
var options = { desiredCapabilities: { browserName: 'chrome' } };
var client = webdriverio.remote(options);
client
    .init()
    .url('https://duckduckgo.com/')
    .setValue('#search_form_input_homepage', 'WebdriverIO')
    .click('#search_button_homepage')
    .getTitle()
    .then(function(title) {
        console.log('Title is: ' + title);
        // outputs: "Title is: WebdriverIO (Software) at DuckDuckGo"
    })
    .end();

Using the above approach, you will always have to chain your commands, but you can also use synchronous commands inside the .then() statement.

For debug purposes, WebdriverIO comes out-of-the-box with a beautifully designed Read-Eval-Print-Loop (REPL inferface) in the form of the .debug() command. Just add it into your test-case prior to where you want the execution to stop so you can debug inside your terminal of choice.

!!! Note: The default timeout for the .debug() command is short. Make sure you increase it.


If you find the above approach a pain-in-the-arse, then why not use the WDIO test-runner to make your life easier? You can start by running the wizard:

// if you installed the package globally, or you have the wdio
// binary in your PATH
wdio config 
// or. from the root of your project
./node_nodules/.bin/wdio config

The above will spawn the wdio.conf.js file in your project root. It will be used by the test-runner to run your test-cases. The test-runner also abstracts the initialization of your .client(), you you won't been to deal with it anymore. Just pick a framework to run your test-cases (Mocha, Cucumber, or Jasmine) and start writing your tests.

!!! Note: From now on, browser will be your driver object. Also, make sure you have the wdio.conf.js file configured to support this way of running your test cases: Set the sync-flag to support this approach: sync: true. You can run your tests via the wdio wdio.conf.js command.

Your tests should look like this (using Mocha):

var expect = require('chai').expect;

describe("Testing Robots Emporium Test Suite", function() {

    beforeEach(function() {
        // ==> Your setup here <==
        browser.url('http://www.kevinlamping.com/webdriverio-course-content/index.html')
        var currentUrl = browser.getUrl();
        expect(currentUrl).include("/index.html");        
    })

    it("The FAQs was rendered properly", function() {

        var height = browser.getCssProperty("ul.accordion", 'height');
        // Added a debug step just to show you how easy it is to debug
        browser.debug();
        expect(height.parsed.value).to.be.above(300);
        // The first element was expanded
        var firstItemText = browser.getText('ul.accordion li:nth-of-type(1) div');
        expect(firstItemText).to.contain('be of the metal type.');
    });

    afterEach(function() { 
       // ==> Your cleanup here <==
    });
});

This is my go-to approach. It gives you the best control possible over your test-case execution, but I don't recommend it if your just starting out. Basically it's the above example, but all the commands are chained.

!!! Note: Make sure you have the sync: false flag setup for this.

Let me know if this helps. Cheers!

iamdanchiv
  • 3,828
  • 4
  • 32
  • 40
  • 1
    You have a couple errors in your comment, i.e. `sync: false` should be `sync: true` for synchronous execution, you'll want to include `expect` not `assert` and use `afterEach` for cleanup, not `beforeEach`. – M. Herold Nov 21 '17 at 19:43
  • @M.Herold thanks a lot! You were spot on with the errors. Copy-pasted from a project in haste that day. Cheers mate! – iamdanchiv Nov 21 '17 at 20:33