Test-Driven Infrastructure with Pulumi and Jest

A smoke-tested VPS is a happy VPS
Modern infrastructure development doesn’t have to involve mountains of YAML or some arcane DSL. If you think like a Node.js developer, then infrastructure as code
is just another module — and like every other module, it can (and should) be tested.
Pulumi + Jest = Infrastructure you actually validate
Creating a Hetzner VPS with TypeScript is straightforward:
const vps = new Server(serverName, {
name: serverName,
serverType: "cx22",
image: "ubuntu-22.04",
location: "nbg1",
sshKeys: [sshKey.name],
});
Then comes the firewall — with a single open port:
const firewall = new Firewall(firewallResourceName, {
name: firewallResourceName,
rules: [
{
direction: "in",
protocol: "tcp",
port: "22",
sourceIps: ["0.0.0.0/0", "::/0"],
description: "Allow SSH from anywhere",
},
],
});
The entire infra update process follows a Node-style workflow:
"scripts": {
"preview:prod:critical:vps": "pulumi preview --cwd critical/vps --stack prod",
"prod:critical:vps": "pulumi up --cwd critical/vps --stack prod --yes",
"test": "jest"
}
Testing: not just for applications
Running jest
gives you immediate feedback on whether the infrastructure is actually functioning. We’re not just testing whether “the script ran,” but whether the result is alive and accessible.
Terminal output:
> test
> jest
PASS critical/vps/vps.test.ts (14.711 s)
Hetzner VPS basic checks
✓ server is running and has a public IP (3 ms)
Expected open ports
✓ port 22 should be open (124 ms)
Expected closed ports
✓ port 21 should NOT be open (1148 ms)
✓ port 23 should NOT be open (1029 ms)
✓ port 25 should NOT be open (1037 ms)
✓ port 80 should NOT be open (1037 ms)
✓ port 443 should NOT be open (1034 ms)
✓ port 3306 should NOT be open (1037 ms)
✓ port 5432 should NOT be open (1036 ms)
✓ port 6379 should NOT be open (1035 ms)
✓ port 11211 should NOT be open (1035 ms)
✓ port 8080 should NOT be open (1035 ms)
✓ port 9000 should NOT be open (1034 ms)
✓ port 9100 should NOT be open (1036 ms)
✓ port 9200 should NOT be open (1070 ms)
Test Suites: 1 passed, 1 total
Tests: 15 passed, 15 total
Snapshots: 0 total
Time: 14.739 s, estimated 16 s
Ran all test suites.
Why does this matter?
Because a pulumi up
is not a guarantee that your server is alive, reachable, or secure. With this approach:
- Smoke tests confirm that the VPS is created and has a public IP
- Positive port checks ensure the intended ports are accessible
- Negative port checks verify that everything else stays closed
The whole setup gives you feedback within 15 seconds: the server is alive, nothing unnecessary is exposed, and you’re good to deploy.
If your infrastructure is just another Node module, feel free to treat it like one. Here, npm run test
doesn’t just validate code — it validates the entire environment your app is supposed to run on.
Subscribe to my newsletter
Read articles from Arnold Lovas directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Arnold Lovas
Arnold Lovas
Senior full-stack dev with an AI twist. I build weirdly useful things on my own infrastructure — often before coffee.