All the moving parts in an end-to-end setup

All the moving parts in an end-to-end setup

End-to-end (E2E) testing requires that many things be in just the right place for it to work as expected. In this article, I’ll walk you through all the necessary pieces of a successful E2E setup.

Docker

Docker is a platform that allows developers to build, share, and run containers—well-defined, isolated environments for running applications. It is very versatile: you can even use it as part of your production deployment. Docker allows you to create containers with different pieces of your application. The containers are perfect building blocks for a temporary environment to use in E2E.

Database

The first layer is a database container, most likely prepopulated with some demo data. You can use the container for your development stack and E2E—in this way, it will be easy to start writing tests and then run them in continuous integration (CI). In most cases, this container will not be accessed directly. Instead, all the changes will be done via the backend or the frontend.

Backend

The most elegant solution is using the same docker container for running E2E and deploying to production. In this way, you make sure that what gets deployed has been tested previously. To pull this off, you need a container that gets some configuration from the outside—for example, as a config file. The config file would contain the connection string to the database, as well as other details that differ between environments.

Frontend

For the frontend, we just need the built project and a simple container that hosts them. Depending on your hosting set up, you will use the same image for deployment, or you will have the static files uploaded to the cloud.

E2E framework/tool

The other necessary piece is the tool that we use for writing and running the tests. Each testing framework does things slightly differently, but there is a common structure that we can see in many places.

Test runtime

Usually, there is a separate process that you start from the command line, and it runs your tests. This process controls the browser where the application is run, but these two contexts are isolated. If you run console.log in your test code, this log will appear in the output of your command line.

Browser

To run the tests, we need a browser that will run the application and follow instructions provided by the test runner. Years ago, this was a very clumsy part of the E2E and the source of many complications. Currently, thanks to WebDriver becoming the standard, the testing tools are more easily integrated with different browsers. Even with those improvements, the browser is another piece that needs to be working correctly for the tests to run—when I investigate E2E failures at my work, some issue seems to be caused by the browser failing to start correctly.

Examples

There are many E2E frameworks, but here let’s focus on just two of them.

Cypress

Cypress is a very popular JS tool for writing E2E tests. Since 2021, I’ve been migrating the biggest project I work on to Cypress from Protractor—a deprecated framework for testing Angular application. Main benefits of Cypress that I see are as follows:

  • independence from frontend framework—you can use it with Angular or any other technology
  • test running interface that allows you to conveniently scroll recording of a test run
  • easy to configure video recording—especially helpful for troubleshooting failures in CI.

Playwright

JavaScript is a common language of choice for tools that test web applications, but there are options for other languages too. One of them is Playwright—a testing framework built by Microsoft, that lets you write tests in JS, Python, Java or .NET. In the right circumstances, the language flexibility can be very valuable for the project.

Continuous integration

Continuous integration (CI) is a process in which you verify your code after every change that is made. Usually, it’s integrated with your code repository, and runs the same checks on every commit.

Runners

Runner is a machine started by the CI platform to run CI jobs defined in the configuration file. In the case of E2E, it has plenty of things to do:

  • download and start containers needed by your application—frontend, backend and database,
  • provide all dependencies: the correct language interpreter, browser, code dependencies, etc., and
  • execute the E2E tests.

Examples

Here are some common CI platforms that are worth checking out.

GitLab

GitLab offers a complete platform for software development: from code repository, to issue tracking, continuous integration, deployment, etc. It’s a packaged offer, so it can be especially interesting if you are looking for a complete solution for your code development. I use it a lot at work, and I’m mostly happy with it.

GitHub

GitHub is the biggest code hosting platform that offers CI with GitHub actions. Similarly to GitLab, it could cover most if not all needs related to developing code. The pricing of both depends on the project needs and size. Over time, the offers change, and one or the other can be a better match for your project. Unfortunately, switching between both providers would not be easy—so you are likely to stick to one that you choose.

CircleCI

Very interesting CI–only provider. I have only limited experience using it, but I’m impressed by its speed and clear logs. I’m definitely going to investigate it more thoroughly—at work, and here on the blog.

Summary

E2E is fairly complicated, but it’s an important tool to keep your code base stable and error free. If you are interested in learning more, you can sign up here to get updates when I publish new articles on testing or other programming related topics.