UI Testing with Puppeteer and Mocha — Part 1 (Getting Started)

Ankit Muchhala
Nov 21, 2017 · 6 min read

1. Introduction 🤝

If you have ever built a web app, you know the pain of testing the entire application every time you add a new feature. Yes, you just modified one isolated module of the code and it should not affect anything else. But there a tiny sliver of doubt in a dark corner of your mind, “What if it broke something?”.

To remove this doubt, you spend quite a lot of time testing all other flows to make sure you did not accidentally break anything major. There is always a chance of you missing edge cases. So you go ahead and deploy with the hope that nothing breaks. By no means, is this a reliable way of testing. But we still do it. The only way to get rid of this unreliability is to write tests which verify your flows viz. UI Testing.

This series is an attempt to get you started with UI testing using puppeteer and mocha. It starts from scratch and assumes basic knowledge of JavaScript. Part 1 deals with setting up and getting started with puppeteer.

2. The Toolkit 🎒

2.a Mocha

Mocha is a JavaScript testing framework. It provides a lot of methods like , , , etc. to organise your tests. It provides both command line and programmatic utilities to execute the tests.

2.b Chai

Mocha by itself is not of much help to us. You need an assertion library with it to actually test things. We will use ChaiJS throughout this series. There are other options like expect.js, should.js, etc.

2.c Puppeteer

Puppeteer is a node wrapper around headless Chrome which started shipping with Chrome 59 (For Windows Chrome 60). It provides a lot of convenient methods to access and manipulate DOM, cookies, requests, etc.

We will use these APIs to access the rendered UI elements and run assertions on them to check if things are working as expected.

3. Basic testing setup 🐣

Open your terminal and create a new project. You need Node installed on your computer which will expose a and command. I recommend using nvm to manage node versions. This series uses Node and npm .

mkdir puppeteer-mocha
cd puppeteer-mocha
npm init --yes
npm i --save mocha@4.0.1 puppeteer@0.13.0 chai@4.1.2 http-server@0.10.0

All packages are suffixed with versions to make this future proof. You can skip them if you want. We install to start a basic http server for testing. If you already have a server running with a website, you can simply use that.

Now we will create

  1. Add folder which will contain all the test files
  2. Add folder which house our test website
  3. Add npm scripts for starting our server and running tests
mkdir test src
touch test/sample.spec.js
touch src/index.html

To start off, we will create a very basic website which we can test. Here is what looks like.

Now add the following two scripts to your . The script tells mocha to execute all files in the folder . The recursive option tells it to go inside directories, if any, and get files. The script serves your on

"scripts": {
"test": "mocha --recursive test",
"server": "http-server src"

Finally, let’s add a sample test to check if everything is working as expected. Add the following code to .

Now run and you should see an output like this -

sample test  ✓ should work

🎉 Hurray! We are all set to integrate puppeteer now. You can view code at this stage here.

4. Bringing in Puppeteer 🚂

We want to start one instance of the browser (headless Chrome in this case) and reuse the same instance to run all our tests. Each test will open a new tab, browse to the URL, run tests against the view and then close the tab. We will do all the setup in and expose required variables to be used across tests.


The block is responsible to setup everything required for all the tests. It will execute once before all tests. It exposes the instance and function so that we don’t have to require it in all the test files. The block cleans up the environment, once all tests are completed. I have also used Lodash for some convenience methods.

The important things to note are and . As the name suggests, starts a chrome browser based on the options provided.

  • I have turned off the headless mode with . This will open a Chromium window when you run the test.
  • Added timeout of 10 seconds (any test taking longer than that will fail)
  • Slowed down each operation by . This is not required right now, but comes in handy when you want to see what is happening in the browser.

You need to tweak your test script a little

"scripts": {
"test": "mocha test/bootstrap.js --recursive test",

We will now update . To do something with this browser instance exposed. To check, we just log the browser version.


Now, when you run . You should see the Chrome version logged. The version might differ for you as puppeteer installs the latest version of Chromium available.

sample testChrome/64.0.3264.0   ✓ should work (103ms)

4.a Without using async/await

For many reasons you might not prefer to use syntax. You can achieve the exact same by just using promises. Since most puppeteer functions return promises, all you have to do is wait for them to resolve. The mocha method comes in handy.


I prefer using as it looks cleaner and is much more readable, especially for more complex tests.

You can view the code at this stage here.

5. Writing your first UI test 🚀

Now that we have set things up, it’s time to write tests. This is how our webpage looks right now. Pretty boring! I agree.

Image for post
Image for post
Test webpage

We want to test the following things:

  1. The page title is “Puppeteer Mocha”
  2. The heading is “Page Title” (Sorry for the confusing heading)
  3. There is a paragraph with “Some paragraph text” in it

Puppeteer has a lot of classes like , , , etc. Each of these classes provide helper methods to access and interact with the page content. The usual workflow is to open the page, wait for a selector and then validate the content once the selectors resolve. This is how basic tests look like:


There is a lot going on in this spec file. Let’s look at it one by one.

We first open a new page in the block and navigate to http://localhost:8080. This is equivalent to you opening a new tab in chrome, typing the URL and pressing enter. Since, the variable is defined in the block, all blocks (specs) have access to the page. This allows us to segregate our tests and make them more readable.

The first test simply checks the page title and expects it to be equal to “Puppeteer Mocha”.

The second test checks for the heading. takes two arguments and . It runs a in the browser environment and passes the result to the . Finally, it resolves with the value returned by . In this case, we are just returning the text for tag.

The third test checks for the existence of just one element with class . The expects only the selector as a parameter. It runs a in the browser environment and returns an array of . You can imagine as a wrapper around an HTML element with helper functions which make it easier to interact and test them.

You can view the code at this stage here.

6. Conclusion 💯

In this part we have barely scraped the surface of puppeteer. I hope you have gotten a feel of UI testing. Over the next parts, we will dive deep into testing complex webpages and interactions.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch

Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore

Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store