PHPackages                             mrpunyapal/pest-annotator-plugin - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Testing &amp; Quality](/categories/testing)
4. /
5. mrpunyapal/pest-annotator-plugin

ActiveLibrary[Testing &amp; Quality](/categories/testing)

mrpunyapal/pest-annotator-plugin
================================

A Pest plugin that annotates uncovered classes and methods with clean, colorized output when running pest --coverage.

0.0.4(2mo ago)25MITPHPPHP ^8.3CI passing

Since Feb 28Pushed 1mo agoCompare

[ Source](https://github.com/MrPunyapal/pest-annotator-plugin)[ Packagist](https://packagist.org/packages/mrpunyapal/pest-annotator-plugin)[ RSS](/packages/mrpunyapal-pest-annotator-plugin/feed)WikiDiscussions main Synced 1mo ago

READMEChangelog (4)Dependencies (6)Versions (6)Used By (0)

Pest Annotator
==============

[](#pest-annotator)

A [Pest PHP](https://pestphp.com) plugin that annotates coverage output with class-level details, type coverage, cyclomatic complexity, baseline diffs, and flexible export formats.

Requirements
------------

[](#requirements)

- PHP 8.3+
- Pest PHP 4.0+
- A code coverage driver (Xdebug, PCOV, or PHPDBG)

Installation
------------

[](#installation)

```
composer require --dev mrpunyapal/pest-annotator-plugin
```

Usage
-----

[](#usage)

Run Pest with coverage and any of the `--annotate-*` flags:

```
./vendor/bin/pest --annotate-coverage
```

Or combine individual flags with the standard `--coverage` flag:

```
./vendor/bin/pest --coverage --annotate-methods --annotate-complexity
```

---

Flags Reference
---------------

[](#flags-reference)

### All-in-one entry point

[](#all-in-one-entry-point)

FlagDescription`--annotate-coverage`Enable coverage collection **and** class-level annotations in one flag. Replaces `--coverage --annotate`.`--annotate-coverage=N`Same as above, plus enforce a minimum coverage threshold of `N`%### Coverage Annotations

[](#coverage-annotations)

FlagDescription`--annotate`Show class-level coverage annotations (requires `--coverage`)`--annotate-methods`Show per-method details with line numbers`--annotate-covered`Also include fully covered classes and methods in output### Complexity Analysis

[](#complexity-analysis)

FlagDescription`--annotate-complexity`Show cyclomatic complexity per method, cross-referenced with coverage### Baseline &amp; Diff

[](#baseline--diff)

FlagDescription`--annotate-save-baseline`Save the current coverage report as a baseline (`.pest-annotator-baseline.json`)`--annotate-diff`Show coverage changes relative to the saved baseline### Filtering &amp; Thresholds

[](#filtering--thresholds)

FlagDescription`--annotate-min=N`Exit with a non-zero code if total coverage is below `N`%`--annotate-namespace=Prefix`Restrict output to classes matching the given namespace prefix`--annotate-exclude=Prefix`Exclude classes matching the given namespace prefix### Export

[](#export)

FlagDescription`--annotate-format=FORMAT`Export coverage report (`json`, `markdown`, or `html`)`--annotate-output=PATH`Write the export to `PATH` (defaults to stdout)---

Examples
--------

[](#examples)

### Basic coverage annotations

[](#basic-coverage-annotations)

```
# new single-flag form
./vendor/bin/pest --annotate-coverage

# classic form (still works)
./vendor/bin/pest --coverage --annotate
```

```
  Fully Uncovered Classes

  ░░░░░░░░░░   0.0% (0/3 methods, 0.0% lines) App\Services\InvoiceService

  Partially Covered Classes

  ████████░░  80.0% (4/5 methods, 85.0% lines) App\Jobs\UpdateUserAvatar

  Summary

  Total Classes:      5
  Fully Covered:      3
  Partially Covered:  1
  Fully Uncovered:    1

```

### With per-method details

[](#with-per-method-details)

```
./vendor/bin/pest --coverage --annotate-methods
```

```
  Partially Covered Classes

  ████████░░  80.0% (4/5 methods, 85.0% lines) App\Jobs\UpdateUserAvatar
     ✕ failed() L42-58 (0/8 lines)

```

### Type coverage analysis

[](#type-coverage-analysis)

When using Pest's [type-coverage plugin](https://pestphp.com/docs/type-coverage), combine `--type-coverage` with `--annotate` to get annotated type coverage output:

```
./vendor/bin/pest --type-coverage --annotate
```

```
  Type Coverage

  ██████████  100.0% App\Data\UserDto
  ████████░░   80.0% App\Services\UserService
     missing return type: handle()
     missing param type:  handle() $request

```

> **Note:** `--coverage` and `--type-coverage` are independent features and should not be used together.

### Complexity analysis

[](#complexity-analysis-1)

```
./vendor/bin/pest --coverage --annotate-complexity
```

```
  Complexity Analysis

  App\Services\PaymentService
     processPayment()   complexity: 12   coverage:  30.0%  ⚠ high risk
     refund()           complexity:  3   coverage: 100.0%

```

Methods with complexity ≥ 10 **and** coverage below 50 % are flagged as ⚠ high risk.

### Baseline workflow

[](#baseline-workflow)

Save a baseline after a clean run, then compare on subsequent runs:

```
# save baseline
./vendor/bin/pest --coverage --annotate-save-baseline

# compare against baseline
./vendor/bin/pest --coverage --annotate-diff
```

```
  Coverage Diff

  ↑ App\Services\UserService    75.0% → 90.0%  (+15.0%)
  ↓ App\Jobs\SendEmail          80.0% → 60.0%  (-20.0%)

```

### Minimum coverage threshold

[](#minimum-coverage-threshold)

```
# shorthand: enable coverage + annotations + threshold in one flag
./vendor/bin/pest --annotate-coverage=80

# explicit form (equivalent)
./vendor/bin/pest --coverage --annotate --annotate-min=80
```

Exits with a non-zero status code if total coverage drops below 80 %.

### Namespace filtering

[](#namespace-filtering)

```
# only show App\Services classes
./vendor/bin/pest --coverage --annotate --annotate-namespace=App\\Services

# exclude test helpers
./vendor/bin/pest --coverage --annotate --annotate-exclude=App\\Testing
```

### Export formats

[](#export-formats)

```
# print JSON to stdout
./vendor/bin/pest --coverage --annotate --annotate-format=json

# write Markdown (suitable for PR comments) to a file
./vendor/bin/pest --coverage --annotate --annotate-format=markdown --annotate-output=coverage.md

# write a self-contained HTML report
./vendor/bin/pest --coverage --annotate --annotate-format=html --annotate-output=coverage.html
```

---

How It Works
------------

[](#how-it-works)

1. Hooks into Pest's plugin lifecycle via `HandlesArguments` and `AddsOutput`
2. All `--annotate-*` flags are consumed before they reach Pest/PHPUnit
3. After tests complete, reads the native `CodeCoverage` object
4. Extracts class-level and method-level coverage data including line numbers
5. Optionally analyses PHP files for type declarations (using `nikic/php-parser`) and cyclomatic complexity (using `sebastian/complexity`)
6. Renders annotated output grouped by coverage status, with progress bars and colour indicators

---

Development
-----------

[](#development)

```
git clone https://github.com/mrpunyapal/pest-annotator-plugin.git
cd pest-annotator-plugin
composer install
composer test
```

License
-------

[](#license)

MIT

###  Health Score

39

—

LowBetter than 85% of packages

Maintenance95

Actively maintained with recent releases

Popularity7

Limited adoption so far

Community6

Small or concentrated contributor base

Maturity42

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

4

Last Release

70d ago

PHP version history (2 changes)0.0.1PHP ^8.2

0.0.3PHP ^8.3

### Community

Maintainers

![](https://www.gravatar.com/avatar/230c58a4f918ca3e3f2988b38721230698bce88f76ae9087e4377ba0b3a074d5?d=identicon)[MrPunyapal](/maintainers/MrPunyapal)

---

Top Contributors

[![MrPunyapal](https://avatars.githubusercontent.com/u/53343069?v=4)](https://github.com/MrPunyapal "MrPunyapal (34 commits)")

---

Tags

phpplugintestingpestcoverageannotator

###  Code Quality

TestsPest

Static AnalysisPHPStan, Rector

Code StyleLaravel Pint

Type Coverage Yes

### Embed Badge

![Health badge](/badges/mrpunyapal-pest-annotator-plugin/health.svg)

```
[![Health](https://phpackages.com/badges/mrpunyapal-pest-annotator-plugin/health.svg)](https://phpackages.com/packages/mrpunyapal-pest-annotator-plugin)
```

###  Alternatives

[pestphp/pest-plugin-type-coverage

The Type Coverage plugin for Pest PHP.

343.3M730](/packages/pestphp-pest-plugin-type-coverage)[defstudio/pest-plugin-laravel-expectations

A plugin to add laravel tailored expectations to Pest

98548.9k4](/packages/defstudio-pest-plugin-laravel-expectations)[pestphp/pest-plugin-stressless

Stressless plugin for Pest

67792.6k16](/packages/pestphp-pest-plugin-stressless)[jonpurvis/lawman

A PestPHP Plugin to help with architecture testing SaloonPHP integrations

4027.7k8](/packages/jonpurvis-lawman)[ozzie/pest-plugin-nest

Nest Pest PHP tests for better organization and readability

2028.3k](/packages/ozzie-pest-plugin-nest)[alleyinteractive/pest-plugin-wordpress

WordPress Pest Integration

263.7k1](/packages/alleyinteractive-pest-plugin-wordpress)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
