How we automatically keep our Documentation Screenshots up to date

When you open the Camunda User Guide, you’ll see that there are many screenshots explaining the different functions and options the product offers. We hope that you, as a user, find those screenshots helpful. But for us as developers, creating and keeping those screenshots up to date has always been a pain.


At the time of writing, the user guide for Camunda Optimize contained 94 screenshots. And with every release we add more functionality, which means the number of screenshots continuously grows. When we change the look of buttons or add a new section to the header, we need to update every screenshot that has a button or header in it. In practice, this meant we were manually recreating every screenshot for every release. With almost 100 screenshots, most of which show quite complex situations, simply updating the user guide would take us a day or two.

As developers, and especially as developers of workflow automation tools, we were eager to automate this time-consuming task.

End-to-end Tests to the Rescue

As part of our commitment to deliver high-quality and stable software, all our products are automatically tested. In Optimize, in addition to unit and integration tests, we also use end-to-end testing to ensure that the functionality we describe in the user guide works.

End-to-end testing means that an automated program interacts with the browser in the way a normal user would interact with the site. Clicking on buttons, entering text, navigating around, making sure everything works as expected.

To run those automated tests, we use a library called testcafe. If you look at the “Interact with the Page” section of their documentation, you’ll find all the actions you would expect from such a testing framework. Beside clicking, pressing keys, entering text, there is also a “Take Screenshot” action. This is often used to get a snapshot of the page in case any test fails, so you can see what was going on.

But we were wondering: Could we use this screenshot functionality to escape the realm of testing and help us with the documentation too?


Forming a Plan

We figured out that we can make screenshots of the page while we run the end-to-end tests. But that does not mean that those screenshots are useful for the user guide documentation.

In the user guide, the screenshots have to fit the scenario described in the text. So if we want to automatically create them, we must make sure that the test that produces them is related to the text on the user guide. Our end-to-end tests need to serve two purposes: Testing that the product works as expected, while at the same time creating scenarios that can be used to take screenshots for the user guide.

At this point we pragmatically thought: “Well, by writing features in the documentation we guarantee that these work, so we should have those features covered in end-to-end tests anyway”.

So we took the existing documentation as a guide to go over our existing end-to-end tests and adjust and extend them so they reflect the features described in the user guide documentation. After that, the only thing left to do was to take screenshots at the right moment in the test and put them in the documentation.

Custom Annotations

Sometimes you need more than just a screenshot. You might have UI elements that need more explanation, like in this example:

Invoive Pipeline

We wanted to have a way to add annotations to the screenshot.

The first idea we had was to just create a transparent png and put it above the generated screenshot. This, however, would cause problems if an update changes the position of the elements we want to annotate.

We needed a way to create the annotations with the contextual information of the page. Ideally, the annotation is there when the screenshot is being taken, so it has to be part of the tested code.

Testcafe offers the ability to run a function on the “client-side”, which means in the browser that is running the test. This is meant to get information from the browser, such as the window location or the document URI. But this is just some Javascript that is injected into the tested page and can be triggered by the test code.

So we wrote a snippet that takes an annotation text and css selector for the element to annotate. It then creates a div container and puts it on the page. In the test code it would look like this:


With that, we are able to dynamically add annotations wherever we want and can put the resulting screenshots directly into our documentation without any manual adjustments.

What are the limitations?

While we were able to automate the generation of a majority of the screenshots, some still need to be updated manually. For Optimize this affects primarily dashboards, as the drag and drop operation is poorly supported by testcafe. There is an open issue to improve that.

If the testcafe team implements this, we might come back to this topic once more. For now we enjoy the time we save every release not having to worry about screenshots as much.


  • Camunda Cloud Console Go Client Library

    When working with multiple projects and multiple Cloud Services automation becomes a must. Camunda Cloud resources such as Zeebe Clusters and Camunda Operate are no different from other components such as Databases, or Message brokers, these need to be provisioned for your applications to connect with. This project allows you to connect to the Camunda Cloud Console using the Go language or a command-line tool, allowing you to create automation around when remote environments are created and destroyed. You can connect to these APIs using any language as these APIs are just REST endpoints, but if you have automated pipelines using a command-line tool might be the best fit for you.  This project provides a binary that you can download...

    Read more
  • Communication Between Loosely Coupled Microservices

    In our recent webinar titled “Communication Between Loosely Coupled Microservices” we got a lot of great questions and because of the limited time some were left unanswered. As community questions are really important to me I want to follow my tradition to answer remaining questions in a blog post (as I have for example also done roughly a year ago in “Webinar FAQ for Monitoring & Orchestrating Your Microservices Landscape using Workflow Automation”). What Was The Webinar About? You can find the slides (here) and recording (here) online. The webinar covered different styles of communication. This was explained by looking at how ordering food works: Synchronous blocking: A call uses a synchronous protocol, like HTTP, and blocks for the result. This is you, calling a pizza...

    Read more
  • Swagger API access with Camunda Platform

    Have you ever fired up the Camunda Platform Docker instance and wished you could do live-calls to the API via a swagger server? We have! And like most things we wish we could do, we go out and make it happen. Coming Soon To be clear, this integration is coming to the official Camunda Platform Docker container with release 7.15. It’s just not ready yet. So this is really more of an interim solution rather than the be-all and end-all solution, but it works, and it makes sending API calls to a live instance of Camunda Platform a lot easier. So follow along and we’ll show you how to run it yourself. CORS is your friend, and not your friend In general, and...

    Read more