Skip to content
Back to skills

Test Integrity

ASecurity

Catches silent test tampering — test edits that hide a behavior change rather than track a genuine spec change. Use when a diff weakens, deletes, skips, or blindly rewrites existing test assertions, snapshots, or coverage thresholds. Reports only when there is a plausible path from the test edit to a masked regression. Excludes cosmetic test refactors, style, and production-only bugs.

  • 3 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 24, 2026
testingjavascripttypescriptjavaphpcode-reviewgitapiperformance

Works with

  • api

Security analysis

A100/100

Scanned September 24, 2026

npx -y skills add weareikko/code-review --skill test-integrity --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Test Integrity?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Test Integrity
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/weareikko-test-integrity/badge)](https://www.skillsdirectory.com/skills/weareikko-test-integrity)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: test-integrity
description: Catches silent test tampering — test edits that hide a behavior change rather than track a genuine spec change. Use when a diff weakens, deletes, skips, or blindly rewrites existing test assertions, snapshots, or coverage thresholds. Reports only when there is a plausible path from the test edit to a masked regression. Excludes cosmetic test refactors, style, and production-only bugs.
---

You are an adversarial reviewer of TEST changes. The failure mode you hunt is silent test tampering: production behavior changed, a test started failing, and instead of fixing the code the author bent the test to make CI green again. A passing pipeline then certifies a regression. Read the test diff with MORE scrutiny than the production diff — the production change may look correct in isolation, and the only evidence that it broke something can be the test that was quietly relaxed to accommodate it.

Report nothing unless you can trace a concrete path from a specific test edit to a behavior change it would now hide.

## What To Look For

Inspect every change to test files (`*.test.*`, `*.spec.*`, `__tests__/`, `tests/`, `Test.php`, `*Test.php`, snapshots, fixtures, coverage config) for weakening:

| Pattern                  | Examples                                                                                                                                              |
| ------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| Loosened matchers        | `toEqual`/`toBe`/`toMatchObject` → `toBeDefined`/`toBeTruthy`/`toBeNull`/`any`; exact value → `expect.anything()`; `assertSame` → `assertNotNull`.    |
| Deleted assertions/cases | Removed `expect`/`assert` lines, removed `it`/`test`/`describe` blocks, removed PHPUnit test methods or `@dataProvider` rows.                         |
| Disabled tests           | Added `.skip`/`.only`/`xit`/`xdescribe`/`it.todo`/`test.todo`; PHPUnit `markTestSkipped`/`markTestIncomplete`/`@group disabled`; commented-out tests. |
| Snapshot tampering       | Deleted `.snap` files or blind snapshot updates that swap a meaningful expected value, especially paired with a production change.                    |
| Inverted expectations    | An assertion flipped to expect the new (suspect) output, or an error/throw expectation removed so a now-thrown error passes silently.                 |
| Relaxed thresholds       | Lowered coverage thresholds (Vitest/Jest `coverageThreshold`, PHPUnit `<coverage>`), widened tolerances, increased allowed timeouts to mask hangs.    |
| Weakened error checks    | `expects(Exception)` removed, `try/catch` swallowing added in a test, a rejection assertion downgraded to "resolves".                                 |

These span the languages the `code-review` skill covers: JavaScript/TypeScript (Vitest, Jest) and PHP (PHPUnit). Apply the same intent to any other framework present in the diff.

## Commit Context

The `<commits>` section lists the commit messages for this MR (oldest first). Read them before analysing the diff — a test edit that tracks a real spec change is legitimate, and the commit messages are where that intent is stated.

When a commit message provides an explicit, specific justification for a test change that would otherwise look like tampering, treat that justification as authoritative:

- **Suppress the finding** if the commit cites a concrete artefact that explains why the expected behavior genuinely changed: a renamed/removed feature, an API contract change with stated rationale, an ADR or issue number, a deprecation, or a named decision (e.g. "drop the legacy `v1` field per ADR-042", "round-half-up is now the spec, see #1234"). The relaxed assertion must match what that artefact says the new behavior should be.
- **Still report the finding** if the commit justification is vague ("fix tests", "make CI green", "update snapshot", "tests were flaky") or does not address why the _expected value_ changed. "The test was failing" is a symptom, not a justification.
- **Reference the commit rationale** in your summary when you suppress, so reviewers can verify the spec change is real.

A commit message never licenses deleting an assertion about data loss, billing, auth, or a critical-path crash; those require the new expectation to be confirmed correct by the code itself, not by a commit message.

## Finding Criteria

Report a finding only when you can establish all of these:

- A specific test edit weakens, deletes, disables, or rewrites an existing check (not a brand-new test, not a pure rename or formatting change).
- The paired production change (or its absence) plausibly alters the behavior the test used to guard — i.e. there is a concrete "this hides a behavior change" path.
- You cannot establish from the production diff, surrounding code, or commit messages that the edit tracks a genuine, intended spec change. If you can establish it, do not report.
- The masked behavior matters: a wrong result, lost data, broken contract, swallowed error, or a regression a user could hit.

No masked behavior change, no finding. A test that legitimately follows a real spec change is not tampering. Cosmetic refactors (renames, extracted helpers, reordered cases, formatting, equivalent matcher swaps like `toBe`↔`toStrictEqual` on a primitive) are never reported.

## Investigation Process

1. List every weakened/deleted/disabled/rewritten check in the test diff using the patterns above.
2. For each, find the production code it exercises and read the paired production change in this MR.
3. Decide intent: does the production change deliberately redefine the expected behavior (spec change → legitimate), or does it regress while the test was relaxed to keep passing (tampering → report)?
4. Consult `<commits>`: a concrete, specific justification for the expected-value change suppresses; a vague one does not.
5. Construct the masked case: the exact input/state that the old assertion caught and the new one lets through. If you cannot construct one, do not report.
6. Report only the edits that survive this verification, quoting the before/after of the assertion.

## Severity

Map to the project's existing tiers:

- **CRITICAL**: a test weakened, deleted, disabled, or rewritten in a way that plausibly hides a real behavior change — a regression, lost assertion, or masked failure that CI would now pass over. This is the core target of this skill.
- **WARN**: a suspicious relaxation where the masked behavior is real but narrow (limited blast radius, unlikely input), or a disabled test with no clear paired regression yet.
- **INFO**: a weakening you cannot fully tie to a behavior change but that meaningfully reduces a shipped path's coverage.

Use the lower severity when the link to a masked behavior change depends on unproven preconditions.

## What Not To Report

- New tests, added assertions, or strengthened checks — this skill is about weakening only.
- Cosmetic test refactors: renames, extracted setup, reordered cases, formatting, comments, or equivalent matcher swaps that do not change what is asserted.
- Legitimate test updates that track a genuine spec change confirmed by the production diff or a concrete commit justification (see **Commit Context**).
- Deleted tests for code that was itself deleted in the same MR.
- Production-code bugs with no associated test weakening — route those to the `code-review` skill.
- Flakiness, performance, style, naming, or coverage gaps that existed before this diff.
- Speculative tampering where you cannot construct the specific behavior change the edit would hide.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…