Manveen Singh

149 tests for a few Slack buttons

My task tracker is a few Slack buttons and two n8n workflows. It has 149 tests. That's because my email scheduler once said Success every day for a week and sent nothing.

My task tracker lives in Slack. Every task has buttons: done, snooze, blocked. A click goes to an n8n webhook, a web address n8n listens on, which checks the click really came from Slack, writes it to a GitHub repo and updates the card, all in under a second. Behind those buttons sit two n8n workflows with 37 nodes between them.

They have 149 tests. That's four tests a node, which sounds like a lot until you've had a week like the one below.

A week of green ticks

My email scheduler is an n8n workflow too. For a week, every run ended like this:

Status: Success 0 emails sent

A Gmail login had expired. Every node ran, so n8n was telling the truth. Nothing in the workflow treated "no email went out" as a failure, so for a week my emails to prospective clients just didn't go, and nobody noticed, including me.

Now an email only counts as sent when Gmail hands back a message ID and it's saved next to the row, and a health check counts the overdue ones. The tracker I built after that got tested like software, in five layers.

1. The JavaScript doesn't live in n8n

n8n's Code node is a fine place to write code and a bad place to keep it. Mine lives in plain files, and the build pastes it into the workflow. 59 tests run that exact code outside n8n first: a good Slack signature passes, a bad, missing or old one is refused, every button goes to the right action, and clicks from anyone but me are dropped.

2. The workflow file gets checked too

28 tests read the workflow JSON as it sits in git: nodes in the right order, only node types I expect, and credentials referred to by name, never by value. One of them compares every Code node with what the build makes from the tested files, so the workflow can't quietly drift away from the code I tested.

3. Real clicks, replayed

A script takes a recorded Slack click, signs it the way Slack does and fires it at the live webhook. A pass means the webhook answers OK in under a second and exactly one new event file lands in the repo. Slack gives a button 3 seconds to get an answer, so under one leaves room. The same click signed with the wrong secret has to fail, and the replay script has 20 tests of its own.

4. Deploys come from a script

One command creates or updates both workflows and their credentials. Run it twice and the second run updates by name, so there's never a "My workflow (copy)". Credentials come from a private settings file and are never printed, even when an error from the server tries to echo one back. 25 tests.

5. Email links a robot can't press

The tracker also emails me, and some of those emails have buttons. Email security scanners open links to check them before you do, so if opening a link did the thing, a robot would press every button. Each of my links is signed and opens a confirm page. Opening the page changes nothing; only its button writes the event. 17 tests.

GET /confirm → changes nothing robots click links too

What I'd steal from this

  • Keep Code-node JavaScript in files and test it outside n8n.
  • Count a real result, a message ID or a written file, never the word "Success".
  • Keep the workflow JSON in git and test it there.
  • Make every link in an email safe to open.
  • Deploy with a script you can run twice.

149 tests is a lot for a few buttons. It's still cheaper than another week of Success with nothing sent.

Same lesson, other project: in my post Things AI got confidently wrong, 12 tests passed while a morning run crashed for three weeks, because none of them opened the new files.

More writing

← all writingHomeWrite to me