End-to-end testing Single Page Apps and Node.js APIs with Cucumber.js and Puppeteer

What are Cucumber.js and Puppeteer?

They are two Node.js modules that focus on two very distinct areas of software, but the combination of them will allow you to test your web applications regardless of what frontend and backend libraries you are using.

Cucumber

  • What are we trying to accomplish? (action)
  • Who is trying to accomplish it? (stakeholder)
  • Why are they trying to accomplish it? (business value)
A GitHub gist of what the Cucumber feature file would look like at this stage
npm i cucumber -D
npx cucumber-js
  • Look for files with the .feature file extension in the features folder
  • Look for files that contain step definition functions
  • Look for a hooks.js file in the features folder
  • Look for a world.js file in the features folder
  • Look for any step definition functions that are in the step_definitions folder
  • Parse the feature files for Cucumber scenarios
  • Parse the steps in each of those Cucumber scenarios
  • Find any step definition functions that match with those steps
  • For any steps that don’t have matching step definition functions, output sample code to the command line

Puppeteer

  • Load a website, and start navigating around it through clicking links
  • Generate screenshots and PDFs of pages
  • Crawl through links on a Single Page App, whether for a web spider or doing some page caching for server-side rendering.
  • Fill in form fields and click buttons to automate form submission (as part of a business process automation project)
  • Capture timeline trace data of a site loading, in order to benchmark site loading performance.
  • And of course, you can use it to do automated testing of a web application.
npm i puppeteer

Integrating Cucumber and Puppeteer

Now that have an idea of what Cucumber and Puppeteer do, the next question that emerges is how to combine them for testing a web application?

module.exports = {};
  • Flush the database tables of data in the web application before a Cucumber scenario starts, so that we have a clean state beforehand.
  • Wipe the Puppeteer browser of any cookies after every scenario has run, so that we don’t have those cookies leak into the state of the next Cucumber scenario.
  • Close down any browser windows opened by Puppeteer after all of the Cucumber scenarios have finished running.
  • Issue a command to shut down the web app after all of the Cucumber scenarios have finished running.

Loading the Single Page App and API in your Cucumber tests

In traditional web applications, the web application contained both the backend and the frontend, which made doing End-to-end testing on the web application easy to setup. Step forward to today, and web applications can now consist of a separate frontend web application that works in combination with a separate backend application, the API.

npm init
  • It is using Express to do the task of loading the frontend application
  • It is using Express to serve the contents of the build folder (the folder which contains the compiled version of the frontend application)
  • It will respond to other HTTP requests by serving up the index.html file in the build folder.
  • It wraps the express server in another library called ‘http-shutdown’. This library will allow us to gracefully shutdown the web app when we are finished with using it in our Cucumber tests.
  • We attach the hostname of the web frontend to the server, so that we can lookup this value in our Cucumber tests for Puppeteer to load the web application in the browser.
  • We finally export the server as the object returned by the index.js file.
npm i PATH_TO_FRONTEND_GIT_REPOSITORY --save
npm i PATH_TO_BACKEND_GIT_REPOSITORY --save
"dependencies": {
"api": "GIT_PATH_FOR_API_REPO",
"cucumber": "^4.2.1",
"puppeteer": "^1.5.0",
"web": "GIT_PATH_FOR_WEB_REPO"
},
npm link ../PATH_TO_FRONTEND_APP
npm link ../PATH_TO_BACKEND_APP

Writing the code for the step definitions

The step definitions code is where you turn the Cucumber feature files into test code that actually does things to your web application and database, and checks that everything worked as expected.

  • Put the code for the step definition functions in a separate file, and export them from that file. This allows you to structure the step definition matchers in a easy to read format.
  • Give the step definition functions meaningful names that reflect the nature of what they do.
  • Use async/await in your step definition functions, because it will give you the ability to combine them for other step definition matchers, and it will make reading your files easier.
  • Use separate files to store objects that reference urls that can exist in your app, as well as CSS selectors that you want to use to select elements on a page and interact with them (or check that they exist).
  • Use scope.context to store references that can enable to check the last page that was accessed, so that you can write your cucumber feature steps in a more human-like form, rather than constantly passing around references in an explicit form.

Loading your SPA and API for testing

When you’re running your local copies of the SPA and API, you’ll likely have a development environment config, so when you want to run integration tests on them, you’ll want to switch to a test environment configuration, that way you don’t clobber the state of your development environment every time you want to run tests.

“config”: “node scripts/generateWebConfig.js”,
“scripts”: {
“build”: “npm run config && react-scripts build”,
“config”: “node scripts/generateWebConfig.js”,
"scripts": {
"pretest": "NODE_ENV=test npm explore web -- npm run build",
"test": "NODE_ENV=test npx cucumber-js --no-strict",
"posttest": "NODE_ENV=development npm explore web -- npm run config",

Conclusion

This pretty much covers most of what is involved with being able to test your Single Page Apps and APIs with Cucumber.js and Puppeteer.

About Anephenix

Anephenix is my software consultancy, and I’m currently available for new projects.

--

--

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
Anephenix

Anephenix

A digital studio specialising in making web products and services