Can I use jest to run webdriverio tests?

Can I use jest to run webdriverio tests?

You have a web app and you're using jest for unit testing your components. You're checking out webdriverio to run your UI tests in javascript. Webdriverio comes with its own test runner if you want to use it. But you're already using jest in your codebase. Can you use jest to run your tests using webdriverio?

Short answer: yes. Long answer: maybe not? There's a lot of things that jest does well, but what you need out of unit tests is not the same thing you need out of UI tests. Here's a few reasons why jest is a little awkward for UI testing.

jest is really good at running your tests fast

jest can run all of your spec files in parallel, but you can't really customize it (see this github). Consider this example...

describe('user tests', () => {
  beforeAll(() => {
    browser.login(user)
  })

  test('user goes to home page', () => {
    expect(browser.getText(selector)).toEqual('home')
    // this needs to run before the next spec
    browser.navigateToPage('profile')
  })

  test('user goes to profile', () => {
    expect(browser.getText(selector)).toEqual('profile')
  })
})

In this example, we do more things while re-using (for better or for worse) the same browser session.

If tests need to run in order, you need to use --runInBand when running jest. Being able to run tests fast is part of the point with jest, but running tests sequentially means that you don't get some of those benefits.

Webdriverio strikes a good balance in running your tests in parallel. In your wdio.config.js, you can set the max_instances parameter to set a cap on how many tests you can run in parallel, i.e. if you set it to 2, only 2 tests will run in parallel at once.

jest manages globals well

It gets difficult to do things like setup a browser session before your tests start, and providing an active browser session among your tests. Jest has a hook called globalSetup where you can do some initialization work before your tests start running. However... there's a catch. See this example using global setup

// setup.js
var webdriverio = require('webdriver')

module.exports = async () => {
  // setup browser session
  global.browser = webdriverio.remote({
    desiredCapabilities: {
      browserName: 'chrome'
    }
  })
};

// spec.js

test('it fails', async () => { 
  browser.url('google.com') // browser is undefined
})

Any globals defined in globalSetup can only be accessed within globalTeardown. jest does a really great job at isolating context from different tests and making sure your tests don't rely on some globally set state.

Unfortunately it tends to get a bit in the way occasionally. In this case, the workaround is to create a new browser instance in each spec file that you need it which may or may not be a nuisance to add everywhere like in this example.

var browser = require('./webdriverio-wrapper') // all initialization is done here

describe('happy path test', () => {
  beforeEach(() => {
    browser.init() // here we create the browser session
  })
  afterEach(() => {
    browser.end()
  })
})

You lose synchronous calls to webdriver methods.

One of the nicest selling points for webdriverio is that you can make synchronous calls to browser*:

var text = browser.getText(selector)
expect(text).toEqual('hello world')
  • there is some black magic going on to make this possible. Unfortunately, one of the drawbacks here is losing the context of your promise as described in this Github issue for wdio-sync

Instead of the promise/callback nightmare just to assert text on an element like you do with the base selenium-webdriver javascript bindings

test('check text', (done) => {
  webdriver.findElement(webdriver.By.css(selector)).then((element) {
    return element.getText()
  }).then((text) {
    expect(text).toEqual('hello world')
    done()
  })
})

In this example, we need to

  1. Use 2 promises in order to get the text from an element
  2. Since our assertion is inside a then block, we need to explicitly call done() when our test has finished.

Wrapping up

Jest does a lot of things well and is a go-to for unit testing. After trying to set it up with webdriverio and a legacy codebase, there were enough gotcha's with jest to warrant using webdriverio's built in test runner (which is jasmine and thats a great tool as well). UI tests may or may not do a good job of running parallel, and jest likes to run tests in parallel for speed. Your testing codebase might make use of globals, but the way jest manages your global context could make your tests a lot more verbose. But these are all things that make Jest great for unit tests. The biggest price to pay is losing out on synchronous calls to browser (can be done with async/await nowadays).

You might be interested in…

Menu