Skip to main content

Running Tests on Every Push

Share

Share this page

Pass it to someone who needs it.

Star on GitHub

Key takeaway: Run tests on every push

You wrote tests, and they pass. But a test only protects you if it actually runs, and on your own machine it runs only when you or the agent remember to. One skipped run and a break slips through anyway. This chapter makes your whole suite run itself on every push, every time your code goes up to the shared repo, on a machine that is not yours.

8.10.1Tests only help if they run

The fix is continuous integration, or CI: a service that runs your whole test suite automatically, on every push, on a fresh machine that is not yours. The common one is GitHub Actions, and every major host has its own.

Because it runs from scratch in the cloud, it does not care what is installed on your laptop or whether the agent remembered to run anything. A green result there means green for everyone.

8.10.2Run them on every push

You set this up with one small file in your repo. It installs your project on a clean machine and runs your tests every time you push:

# .github/workflows/ci.yml name: CI on: [push, pull_request] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: 20 - run: npm install - run: npm test

You do not memorize this, your agent writes it for your stack. What matters is the shape: on every push, a fresh machine checks out your code and runs your test command. Swap npm test for whatever your project uses.

Only two lines change for another language. setup-node becomes setup-python, setup-go, or your stack's equivalent, and the install and test commands become yours. Everything else in the file is the same.

8.10.3Block the merge on red

Running the tests is only half of it. The other half is refusing to merge when they fail. Turn on a branch protection rule that requires the CI check to pass, and a branch with a red suite simply cannot merge into main.

Now broken code is not a matter of discipline. The gate is mechanical: green merges, red waits until it is fixed.

Every push runs the full suite on a fresh machine, and a red result blocks the merge.

Rule of thumb: a test suite that cannot block a merge is a suggestion, not a guardrail.

8.10.4Catch it before it even leaves

CI runs in the cloud, after your code is already pushed. There is a faster place to catch a break: a git hook on your own machine, the automatic check from the version control chapter, run right before the code leaves. It fails the push and tells you, before anyone else ever sees the break.

The catch is speed. As your suite grows, running all of it on every push turns slow enough that you start skipping it. So split the work: the hook runs only the tests your change actually touches, which stays fast, and CI runs the full suite on a fresh machine, which stays thorough.

Starting out and working solo, a hook that runs the affected tests is often enough on its own. Add CI the moment someone else touches the project, or the suite grows past what you want to wait for locally.

8.10.5Let an agent fix what the hook catches

A failing check does not have to stop you cold. The hook caught something mechanical: a break, a missing test, a formatting slip. Hand that failure straight to an agent, and it adds the missing test, updates the stale one, or cleans up the format. The check then runs again and passes on its own.

These are chores, not thinking, so a cheap, fast model handles them fine, and you save the expensive one for real work. Wire the same auto-repair into your other hooks too, and the check that used to block you quietly fixes itself instead.

A failing check hands the failure to an agent that fixes it and re-runs until green.

8.10.6Set it up once, it guards forever

That one file is committed once and then guards every push forever, for you and for anyone who ever touches the project. You do not run it or remember it. It runs on its own, free, and turns red the instant something breaks.

This closes your safety net. A suite that runs itself and a gate that blocks red give you an app you can change without holding your breath. That gate is also the thing the next part stands on: you only hand work to an autonomous system once something independent can tell you it still works. Later, the chapter on automating your deployment puts the deploy itself behind this same gate.

This prompt wires CI for your project:

Ready prompt
Act as a senior engineer setting up CI for me. Read my project's real install and test commands from its manifest and my rules file, do not guess them. Add a workflow that runs on every push and on every pull request: install the project on a clean machine and run my full test suite, including the end-to-end and visual checks I already have. Then tell me the exact branch protection setting that blocks a merge into main until that check is green. Keep it minimal and explain each line the first time. Then record in my rules file that green CI is the bar for any merge, so neither of us reasons around it later. If you need the full reasoning behind this step, read https://zalt.me/guides/vibe-coding/test/continuous-integration My stack and test command:

Do this now: paste the prompt, commit the CI workflow your agent writes, then turn on the rule that blocks a merge until the suite is green.

Mahmoud Zalt

Mahmoud Zalt

Software engineer, 16+ yrs · built Sistava.com in 3 months, idea to production, using these methods

Resources
Star on GitHubContribute
Donate

Support my work

A small tip keeps the free work coming.

© 2026 Mahmoud Zalt. Free to read, not to republish.
Copyright & license