DEV Community

Adam Gardner
Adam Gardner

Posted on

Automated Markdown Testing: Two Options

Recently I've been writing a lot of tech tutorials at work. These usually comprise of a Markdown file mixed in with code snippets. A user follows the instructions and executes the code snippets at the correct time.

For example:

kind create cluster --config=config.yaml
kubectl get namespaces
Enter fullscreen mode Exit fullscreen mode

As I started scaling these tutorials, it became apparently that they could be flaky if / when the underlying technology changed or was updated. Obviously, the problem gets worse the more complexity and piece of tech that are involved in the tutorial.

Option 1: codedown

I need a way to take that Markdown and automatically run the snippets in a "unit test".

One solution is a brilliant, simple project I discovered called codedown which extracts the snippet from Markdown.

I can then pipe that to a new file and execute that file as a single e2e test:

cat index.md | codedown shell > e2e.sh
chmod +x e2e.sh
./e2e.sh
Enter fullscreen mode Exit fullscreen mode

Option 2: mkdocs snippets

I write and host the tutorials as Markdown using the mkdocs material theme.

An alternative that I'm experimenting with is to keep the entire e2e instructions in a single file, annotating that file in a particular syntax and using the mkdocs snippets extension to include parts of the code at relevant places.

For example, imagine the docs are hosted in docs and this is the e2e shell script docs/e2e/script.sh:

#!/bin/sh
kind create cluster --config=config.yaml
kubectl create namespace foo

kubectl apply -f ingress.yaml

kubectl create namespace bar

kubectl apply -f app.yaml
Enter fullscreen mode Exit fullscreen mode

I could use the snippets extension my mkdocs.yaml file:

site_name: An Example Tutorial
nav:
  - Homepage: index.md
theme:
  name: material
markdown_extensions:
  - pymdownx.snippets:
      base_path: ["docs"]
Enter fullscreen mode Exit fullscreen mode

Then adjust docs/e2e/script.sh - adding annotations to split into logical sections that I want to include:

#!/bin/sh
--8<-- [start:createCluster]
kind create cluster --config=config.yaml
--8<-- [end:createCluster]

--8<-- [start:createFirstNamespace]
kubectl create namespace foo
--8<-- [end: createFirstNamespace]

--8<-- [start:installIngress]
kubectl apply -f ingress.yaml
--8<-- [end:installIngress]

--8<-- [start:createSecondNamespace]
kubectl create namespace bar
--8<-- [end:createSecondNamespace]

--8<-- [start:onboardApp]
kubectl apply -f app.yaml
--8<-- [end:onboardApp]
Enter fullscreen mode Exit fullscreen mode

In the documentation, simply refer to the snippet names wherever you want to include them:

    ## Time to Spin up the cluster

    First, create the cluster:

    ```


    --8<-- "docs/e2e/script.sh:createCluster"


    ```

    ## Create First Namespace

    Create the first namespace and install the ingress.

    ```


    --8<-- "docs/e2e/script.sh:createFirstNamespace"
    --8<-- "docs/e2e/script.sh:installIngress"


    ```
Enter fullscreen mode Exit fullscreen mode

With this method, the e2e.sh script is already ready to run as a single unit.

Summary

I'm still not sure which method I'll end up using, whether I'll find a different way or which is the most scalable (and understandable for other contributors).

I also need to build out the infrastructure to test this (for example when a PR is merged).

Watch this space!

Top comments (0)