PHPackages                             jonpurvis/lawman - 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. [Framework](/categories/framework)
4. /
5. jonpurvis/lawman

ActiveLibrary[Framework](/categories/framework)

jonpurvis/lawman
================

A PestPHP Plugin to help with architecture testing SaloonPHP integrations

v4.2.1(3mo ago)4138.2k↑39.9%[1 PRs](https://github.com/JonPurvis/lawman/pulls)9MITPHPPHP ^8.2CI passing

Since Feb 14Pushed 1w ago2 watchersCompare

[ Source](https://github.com/JonPurvis/lawman)[ Packagist](https://packagist.org/packages/jonpurvis/lawman)[ RSS](/packages/jonpurvis-lawman/feed)WikiDiscussions master Synced 3d ago

READMEChangelog (10)Dependencies (24)Versions (14)Used By (9)

[![](art/banner.png)](art/banner.png)

Lawman - Your Architectural Enforcer for SaloonPHP
==================================================

[](#lawman---your-architectural-enforcer-for-saloonphp)

A PestPHP Plugin for SaloonPHP that helps you enforce architectural rules with your API integrations.

[![Tests](https://github.com/JonPurvis/lawman/actions/workflows/tests.yml/badge.svg)](https://github.com/JonPurvis/lawman/actions/workflows/tests.yml)[![GitHub last commit](https://camo.githubusercontent.com/9362bd4e442757c8a0f2ca667c7ce240a3ff02a46ebe4111bf86863c975b7789/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6173742d636f6d6d69742f6a6f6e7075727669732f6c61776d616e)](https://camo.githubusercontent.com/9362bd4e442757c8a0f2ca667c7ce240a3ff02a46ebe4111bf86863c975b7789/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6173742d636f6d6d69742f6a6f6e7075727669732f6c61776d616e)[![Packagist PHP Version](https://camo.githubusercontent.com/00f8be1c4ed82bc7fc9a8051210bab037b90531366c9aea23a6d600953c75c22/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f646570656e64656e63792d762f6a6f6e7075727669732f6c61776d616e2f706870)](https://camo.githubusercontent.com/00f8be1c4ed82bc7fc9a8051210bab037b90531366c9aea23a6d600953c75c22/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f646570656e64656e63792d762f6a6f6e7075727669732f6c61776d616e2f706870)[![GitHub issues](https://camo.githubusercontent.com/10acf375a7986160084a7c0f6703b3ac52c12dd4375f51d32147338bd0299da9/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6973737565732f6a6f6e7075727669732f6c61776d616e)](https://camo.githubusercontent.com/10acf375a7986160084a7c0f6703b3ac52c12dd4375f51d32147338bd0299da9/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6973737565732f6a6f6e7075727669732f6c61776d616e)[![GitHub](https://camo.githubusercontent.com/a05edcc0a54041d426c5a233fadfe17e94dcd277ea8aa426244040a53410e2ac/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f6a6f6e7075727669732f6c61776d616e)](https://camo.githubusercontent.com/a05edcc0a54041d426c5a233fadfe17e94dcd277ea8aa426244040a53410e2ac/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f6c6963656e73652f6a6f6e7075727669732f6c61776d616e)[![Packagist Downloads](https://camo.githubusercontent.com/a1f7ecc37632e90cb99c25ee772e31e702f784e62d553636ac2e576fc708f8c5/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6a6f6e7075727669732f6c61776d616e)](https://camo.githubusercontent.com/a1f7ecc37632e90cb99c25ee772e31e702f784e62d553636ac2e576fc708f8c5/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f6a6f6e7075727669732f6c61776d616e)

Introduction
------------

[](#introduction)

Lawman is a PestPHP Plugin for SaloonPHP which allows you to easily write architecture tests for your API integrations with a focus on them being easy to write and easy to read. After all, if SaloonPHP makes our API integrations beautiful, the tests for them should be beautiful too, right?

Lawman makes testing your SaloonPHP API integrations, from an architecture point of view, much easier to do. Allowing you to see, at a glance, what a test is actually doing. Lawman is a plugin for PestPHP meaning you can use Lawman Expectations and PestPHP Expectations together, just chain whatever you need for your tests!

Examples
--------

[](#examples)

Let's take a look at how Lawman can help make writing tests easier.

Let's say we have a Connector class that we want to test, with PestPHP we could do the following:

```
test('connector')
    ->expect('App\Http\Integrations\Integration\Connector')
    ->toExtend('Saloon\Http\Connector')
    ->toUse('Saloon\Traits\Plugins\AcceptsJson')
    ->toUse('Saloon\Traits\Plugins\AlwaysThrowOnErrors');
```

So that test is ensuring our class extends the base Connector and uses the `AcceptJson` and `AlwaysThrowOnErrors` traits. Whilst that test works, we could perhaps make it quicker to write and easier to read, so with Lawman, you can do:

```
test('connector')
    ->expect('App\Http\Integrations\Integration\Connector')
    ->toBeSaloonConnector()
    ->toUseAcceptsJsonTrait()
    ->toUseAlwaysThrowOnErrorsTrait();
```

Next up, let's take a Request test that we have:

```
test('request')
    ->expect('App\Http\Integrations\Integration\Requests\Request')
    ->toExtend('\Saloon\Http\Request')
    ->toImplement('Saloon\Contracts\Body\HasBody')
    ->toUse('Saloon\Traits\Body\HasFormBody')
    ->toUse('Saloon\Traits\Plugins\AcceptsJson');
```

Lawman makes this test much nicer to read:

```
test('request')
    ->expect('App\Http\Integrations\Integration\Requests\Request')
    ->toBeSaloonRequest()
    ->toSendPostRequest()
    ->toHaveFormBody()
    ->toUseAcceptsJsonTrait();
```

What about if we want to test our Connector has an Authentication method? Lawman makes this easy to do, it even works with multi auth:

```
test('connector')
    ->expect('App\Http\Integrations\Integration\Connector')
    ->toBeSaloonConnector()
    ->toUseCertificateAuthentication()
    ->toUseTokenAuthentication();
```

Lawman also has Expectations for the Pagination, Cache and Rate Limit Plugins:

```
test('request')
    ->expect('App\Http\Integrations\Integration\Requests\Request')
    ->toBeSaloonRequest()
    ->toSendPostRequest()
    ->toUsePagedPagination()
    ->toHaveCaching()
    ->toHaveRateLimits()
```

Maybe our Connector has some Retry instructions that we want to test. Again, with Lawman, it's as simple as:

```
test('connector')
    ->expect('App\Http\Integrations\Integration\Connector')
    ->toBeSaloonConnector()
    ->toBeTriedAgainOnFailure(tries: 3)
    ->toHaveRetryInterval(retryInterval: 1500)
    ->toUseExponentialBackoff()
```

Maybe our Connector is for an API that tends to be quite slow, so we increased some timeouts:

```
test('connector')
    ->expect('App\Http\Integrations\Integration\Connector')
    ->toBeSaloonConnector()
    ->toSetConnectTimeout(connectTimeout: 30)
    ->toSetRequestTimeout(requestTimeout: 60)
    ->toUseExponentialBackoff()
```

Contributing
------------

[](#contributing)

Contributions to the package are more than welcome so if you think of an Expectation you'd like to see, feel free to submit a Pull Request or Open an Issue. If you do submit a Pull Request, please make sure you add a new Fixture and test for your Expectation(s).

Useful Links
------------

[](#useful-links)

- [Lawman Documentation](https://docs.saloon.dev/installable-plugins/lawman)
- [SaloonPHP](https://docs.saloon.dev/)
- [PestPHP](https://pestphp.com/)

###  Health Score

56

—

FairBetter than 97% of packages

Maintenance91

Actively maintained with recent releases

Popularity39

Limited adoption so far

Community18

Small or concentrated contributor base

Maturity62

Established project with proven stability

 Bus Factor1

Top contributor holds 94.7% 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 ~77 days

Recently: every ~139 days

Total

11

Last Release

98d ago

Major Versions

v1.2.0 → v2.0.02024-08-26

v2.0.0 → v3.0.02024-09-09

v3.1.0 → v4.0.02025-03-01

PHP version history (2 changes)v1.0.0PHP ^8.1

v2.0.0PHP ^8.2

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/7534029?v=4)[jp](/maintainers/JonPurvis)[@JonPurvis](https://github.com/JonPurvis)

---

Top Contributors

[![JonPurvis](https://avatars.githubusercontent.com/u/7534029?v=4)](https://github.com/JonPurvis "JonPurvis (18 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (1 commits)")

---

Tags

frameworkpestphpphpunitpluginsaloontestphpplugintestingunitframeworktestpestsaloon

###  Code Quality

Static AnalysisPHPStan

### Embed Badge

![Health badge](/badges/jonpurvis-lawman/health.svg)

```
[![Health](https://phpackages.com/badges/jonpurvis-lawman/health.svg)](https://phpackages.com/packages/jonpurvis-lawman)
```

###  Alternatives

[pestphp/pest

The elegant PHP Testing Framework.

11.6k72.2M20.6k](/packages/pestphp-pest)[defstudio/pest-plugin-laravel-expectations

A plugin to add laravel tailored expectations to Pest

99600.5k8](/packages/defstudio-pest-plugin-laravel-expectations)[pestphp/pest-plugin-arch

The Arch plugin for Pest PHP.

4358.2M5.5k](/packages/pestphp-pest-plugin-arch)[pestphp/pest-plugin-browser

Pest plugin to test browser interactions

1343.7M186](/packages/pestphp-pest-plugin-browser)[pestphp/pest-plugin-type-coverage

The Type Coverage plugin for Pest PHP.

354.3M1.1k](/packages/pestphp-pest-plugin-type-coverage)[pestphp/pest-plugin-stressless

Stressless plugin for Pest

681.0M18](/packages/pestphp-pest-plugin-stressless)

PHPackages © 2026

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