Diffy: Anatomy of an Advanced DDEV Add-on

August 13, 2024 3 min read

Edit this page
Microsoft image creator: dismantled photo camera.
Microsoft image creator: dismantled photo camera.

Diffy is a visual regression testing tool that allows you to take screenshots of your website and compare them so you know exactly what pages got changed and where. We decided to build DDEV integration so it is possible to take screenshots from the local website, upload them to Diffy, and then compare them with screenshots from other environments.

The ddev-diffy add-on is at github.com/DiffyWebsite/ddev-diffy.

Add-on can be installed with a simple ddev get DiffyWebsite/ddev-diffy. Check the introduction blog post about the installation.

Check our documentation.

Architecturally, integration consists of:

  • Docker container with preinstalled node and Chrome 111
  • Node.js app that runs Chrome
  • The app itself is hosted in a separate repository as it is used in other places (like production for the main service itself).

Let’s go through the way integration is built.

Download node app

To download the app we use install.yaml post_install_actions:

- rm -rf diffy-worker && mkdir diffy-worker
- docker run -it --rm -v ./diffy-worker:/diffy-worker --user $DDEV_UID:$DDEV_GID ddev/ddev-utilities bash -c "cd /diffy-worker && wget -qO- https://github.com/DiffyWebsite/diffy-worker/archive/refs/heads/main.tar.gz | tar xz --strip-components=1"

This is a particularly interesting approach as we use ddev-utilities to download the code and unpack it.

App configuration

The app itself requires API Key and Project ID. Best practice is not to commit them so they are saved manually as .env file.

Run npm install

We want to run npm install inside of the container and not on the host. We accomplished it by adding post-start hook and specifying the service where to run the command. For that we created config.diffy.yaml and had instructions there. Pay attention that it is specified as project_files in install.yaml file.

Docker container user

For security reasons it is important not to run all the processes in our container as root user. For that we create specify a user to run all commands in the container.

See user: '$DDEV_UID:$DDEV_GID' in docker-compose.diffy.yaml and the way we download the code above.

Another interesting trick is that if that user tries to run npm install system will populate ~/.cache folder with some files. But as the user doesn’t not exist we need to ensure that /.cache folder is available and writeable. For that we create it in the container itself.

Building Docker container for multiple architectures

We follow DDEV path to build the Docker container for multiple architectures:

docker buildx build --push --platform $(BUILD_ARCHS) -t $(DOCKER_REPO):$(VERSION) --label "build-info=$(DOCKER_REPO):$(VERSION) commit=$(shell git describe --tags --always) built $$(date) by $$(id -un) on $$(hostname)" --label "maintainer=Diffy <[email protected]>" $(DOCKER_ARGS) .

See Makefile and Readme for more details.

The biggest roadblock I had with the container is that default shell from ubuntu:22.04 is “dash”. So we had to replace it with bash to make node installed and used properly. Also pay attention that we install node with “n” so it is installed to /usr/local/bin/node so it is accessible for everyone.

I would like to thank Randy and Stas as lot for their constant support in this project.

Posted In