BlogDocsProduct Log in Start free
Behind Hawzu

Deleting a Test Case Shouldn't Delete the Evidence

Deleting a test case in Hawzu hides it and leaves every run that used it intact. It also owes three quieter debts — and it deliberately doesn't offer you an undo.

A test case fading out of a repository while the runs that exercised it stay fully lit and unchanged.

Somebody clears out forty obsolete test cases on a Friday afternoon. Old onboarding flows, a payment provider you stopped using, a feature that shipped and got removed. Good housekeeping.

The interesting question isn’t whether those forty are gone. It’s what just happened to every run that ever exercised them — the execution history, the release sign-offs, the audit answer for last quarter.

In a tool where a run points at its test cases, the answer is: quite a lot, silently. Forty rows in old runs now reference something that isn’t there.

Delete is the most dangerous button in a QA tool

It’s dangerous in a specific and unusual way. Most destructive actions announce themselves — you notice a deleted file, a dropped table, a missing page. A deleted test case is the opposite. It removes the thing, and everything that referred to the thing keeps rendering, keeps counting, keeps appearing in reports. The damage is entirely in the past tense and entirely invisible from the present.

The worst deletes aren’t the ones you notice. They’re the ones that quietly change what history says.

So the first decision is that deleting a test case in Hawzu doesn’t remove the document. It flips a status field, stamps who did it and when, and every read path filters on that status. The case disappears from the repository, from search, from pickers. The bytes stay where they are.

That’s not clever. It’s the standard move. What’s worth writing down is everything else the delete has to do at the same time — and the thing it deliberately doesn’t do.

A delete owes four things

Hiding the row is only the first, and it’s the one everybody remembers.

The second one is the interesting one, because it’s the easiest to omit and the most invisible when omitted. Nothing breaks. No error appears. Six months later a chart is quietly wrong and nobody can say when it started.

Both delete paths — deleting a case directly, and deleting a folder full of them — go through one function for exactly this reason. Two call sites doing three of the four things correctly is the realistic failure, not one call site doing all four.

It does not owe you an undo

There is no restore. No trash, no recycle bin, no 30-day window.

This is worth being blunt about, because “soft delete” sounds like it implies undo, and it doesn’t. The code is blunt about it too — the delete function carries a comment reserving the spot where restore would go, and noting that the recycle bin which would have owned it was dead code and got removed.

Soft delete here buys one thing: history stays honest. Deleting a case doesn’t touch a single execution record. Every run that exercised it still holds its own frozen copy — the title, the steps, the dataset, the verdict, the evidence — and reads exactly as it did before, because a run copies the case rather than pointing at it. The delete removes the case from your future. It has no reach into your past.

That’s the whole promise, and it’s smaller than “safe deletion” usually implies. Better to say what it is.

Soft delete isn’t uniform, and pretending otherwise causes bugs

Here’s an unglamorous admission that turns out to matter.

Test cases, requirements and executions mark deletion with a status field. Defects and releases use a separate boolean instead. Releases don’t even declare that field on the model — it’s written by the code that sets it.

Three conventions for one idea, arrived at the way these things always are: each was locally reasonable when it was written. It’s fine right up until something has to query across all of them, at which point every consumer needs to know which convention each collection uses, and a consumer that assumes wrong returns deleted rows while looking completely correct.

We resolved it by making the discrepancy explicit in the one place that reads across everything, rather than by a migration nobody had budget for. Not elegant. Honest, and cheaper than being wrong.

The one place things really get deleted

For completeness: hard deletion does exist, at exactly one scale — purging a whole project after it’s been deleted and served out a grace period.

That path is driven by a declarative manifest classifying every project-scoped collection as either purge-this or keep-this, and a test turns CI red when a new collection appears in neither list. The failure it prevents is a new feature shipping a new collection that quietly survives project deletion for years, holding customer data nobody remembers exists.

Which is the same principle as the terminal time-series row, one level up: the dangerous part of deleting isn’t what you remove, it’s what you forget to.

The practical payoff is that a suite can be pruned on a schedule. Once deleting a case can’t damage the runs that used it, retiring tests becomes routine maintenance rather than a risk.

Deleting a test case should change your future. It should have no reach into your past.

Continue learning