PHPackages                             rawphp/warp - 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. rawphp/warp

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

rawphp/warp
===========

Warm-worker test engine for Laravel + Pest — boots the app once per process and hands each test a sandboxed clone

v0.1.0(3d ago)014↑114.3%MITPHP ^8.4

Since Jul 5Compare

[ Source](https://github.com/rawphp/warp)[ Packagist](https://packagist.org/packages/rawphp/warp)[ Docs](https://github.com/rawphp/warp)[ RSS](/packages/rawphp-warp/feed)WikiDiscussions Synced today

READMEChangelog (2)Dependencies (2)Versions (2)Used By (0)

Warp
====

[](#warp)

**A warm-worker test engine for Laravel + Pest.**

Warp boots your Laravel application **once per PHP process** and hands each test a sandboxed shallow clone of it, instead of paying the full framework bootstrap (~50 ms) on every single test. Classic mode stays the default; warm mode is opt-in per run via `WARP_MODE=1` and is designed to produce **byte-identical outcomes** to classic mode.

Measured results
----------------

[](#measured-results)

Measured on YardPilot's `tests/Feature/Quotes` suite (1,372 DB-backed tests):

GateResult**A — per-test framework tax**classic **53.57 ms/test** → warm **0.55 ms/test** (**97.4× reduction**)**B — outcome parity**`PARITY OK` — all 1,372 tests byte-identical classic vs warm; full suite **2.8× faster** warmMeasured on a large suite (18,921 tests, 12 parallel processes):

MetricClassicWarm**Duration**802.08s314.23s**Failures**1 (timing assertion, run too slow)0**Assertions**54,02454,276**2.55× speedup, 60.8% reduction, 487.9s saved per run.** The classic run's single failure was a timing assertion that blew out under the slower run — warm mode's run had zero failures, which illustrates a secondary benefit: warm mode **eliminates timing-based test flakiness caused by slow cold-boot runs**.

See [`docs/reports/2026-07-04-s1-gate.md`](docs/reports/2026-07-04-s1-gate.md) for the full gate report and [`docs/specs/2026-07-04-warp-test-engine-design.md`](docs/specs/2026-07-04-warp-test-engine-design.md) for the design.

---

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

[](#requirements)

- PHP **8.4+**
- Laravel **13**, Pest **4** (provided by the consuming app — Warp itself requires only `php`)

Warp's `composer.json` requires **only `php`**; every Illuminate class comes from the app that installs it (or from `orchestra/testbench` in Warp's own suite). This guarantees zero version conflicts when path-installed into a host app.

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

[](#installation)

```
composer require --dev rawphp/warp
```

Usage
-----

[](#usage)

### 1. Add the trait to your base `TestCase`

[](#1-add-the-trait-to-your-base-testcase)

Warp wires in through a single trait. Rename your existing `createApplication()` body to `createClassicApplication()` — Warp calls it for the cold boot and, in warm mode, clones the result per test.

```
namespace Tests;

use Illuminate\Foundation\Application;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
use RawPHP\Warp\Concerns\InteractsWithWarmApplication;

abstract class TestCase extends BaseTestCase
{
    use InteractsWithWarmApplication;

    /** Your original cold-boot application factory. */
    protected function createClassicApplication(): Application
    {
        $app = require __DIR__.'/../bootstrap/app.php';
        $app->make(\Illuminate\Contracts\Console\Kernel::class)->bootstrap();

        return $app;
    }
}
```

That's the whole integration. With `WARP_MODE` unset, behaviour is **byte-identical** to before — the trait falls straight through to `createClassicApplication()`.

### 2. Run the suite warm

[](#2-run-the-suite-warm)

```
# Classic (default, unchanged):
./vendor/bin/pest

# Warm mode — boot once, sandbox each test:
WARP_MODE=1 ./vendor/bin/pest
```

With Pest's `--parallel`, every paratest worker becomes warm automatically.

### 3. Customise the reset manifest (when needed)

[](#3-customise-the-reset-manifest-when-needed)

A shallow `clone` of the application shares boot-resolved singletons between sandboxes. The `ResetManifest` handles them declaratively; `ResetManifest::default()` covers Laravel's own stateful services. Override `warpResetManifest()` to add app-specific ones:

```
use RawPHP\Warp\ResetManifest;
use Spatie\Permission\PermissionRegistrar;

protected function warpResetManifest(): ResetManifest
{
    return ResetManifest::default()
        // Spatie's registrar caches permissions per instance — re-resolve fresh per test.
        ->forget(PermissionRegistrar::class);
}
```

`ResetManifest` primitives:

MethodPurpose`forget(string ...$ids)`Drop a stateful leaf service so the sandbox re-resolves it fresh (e.g. `cache`, `session`, `view`).`repoint(string $id, string $property)`Rewrite a shared singleton's back-reference (`$container`/`$app`) to the sandbox without replacing the object (e.g. `router`, `events`, `db`).`flush(string $id, string $method)`Call a public reset method on a per-test service (e.g. `auth` → `forgetGuards`).`add(Closure $step)`A custom `fn ($sandbox, $base) => …` step for anything the primitives don't cover.### 4. Escape hatch — force a classic boot

[](#4-escape-hatch--force-a-classic-boot)

Some tests genuinely can't share a warm base. Opt them out and Warp gives them a fresh cold boot (and skips the hermeticity check):

```
use RawPHP\Warp\Attributes\Isolated;

#[Isolated]
final class NeedsAFreshAppTest extends TestCase { /* … */ }
```

or per-test with a Pest group:

```
it('needs isolation', function () {
    // …
})->group('warp-isolated');
```

Snapshot DB provisioning (S2)
-----------------------------

[](#snapshot-db-provisioning-s2)

`WARP_DB=1` replaces the per-worker `migrate:fresh`/schema-load fixed cost with an instant copy-on-write clone of a **golden datadir** — a fully migrated MySQL data directory built once per schema change and cached under `.warp/snapshots/` (add `.warp/` to your app's `.gitignore`). Each worker gets its own throwaway `mysqld`on a private unix socket, so parallel workers can't collide by construction.

```
# Warm workers + snapshot DB:
WARP_MODE=1 WARP_DB=1 ./vendor/bin/pest --parallel
```

Requirements: MySQL 8 binaries on the machine (`mysqld` + `mysqladmin`; Homebrew, apt, or point `WARP_DB_MYSQLD` at one) and a `mysql`-driver test connection. Per-test isolation is unchanged — `RefreshDatabase` transaction-wraps as before; the golden snapshot just makes its migrate step a no-op.

**Host wiring (required):** the golden build runs as a subprocess with `DB_HOST`, `DB_PORT`, `DB_SOCKET`, `DB_DATABASE`, `DB_USERNAME`, and `DB_PASSWORD`injected into its env, pointed at that worker's throwaway `mysqld`. Your test connection config must read the socket from that env var:

```
// config/database.php — the connection named by config('warp.db.connection')
'mysql' => [
    // ...
    'unix_socket' => env('DB_SOCKET', ''),
],
```

Without it, the build subprocess falls back to whatever socket your driver defaults to instead of the per-worker one warp provisioned — this can silently target the wrong database in a single process, and fails outright (`SQLSTATE[HY000] [2002] No such file or directory`) under `--parallel`.

Optional config, all under `config('warp.db')`:

KeyDefaultPurpose`connection``database.default`Which connection to rewire (must be `mysql` driver)`database`the connection's `database`Schema name baked into the snapshot`hash_paths``database/migrations`, `database/seeders`Files whose content keys the snapshot`build_command``php artisan migrate --force`Command that builds the schema (swap in `--seed` for a fixture universe)`build_env``[]`Extra env for the build command (wins over the injected `DB_*` vars)`snapshot_dir``.warp/snapshots`Golden snapshot cache (env: `WARP_DB_SNAPSHOT_DIR`)`runtime_dir``/tmp/warp-db`Clone + socket dir — keep it short, sockets live here (env: `WARP_DB_RUNTIME_DIR`)`mysqld`auto-discoveredPath to `mysqld` (env: `WARP_DB_MYSQLD`)Tests that must **commit** (DDL, multi-connection assertions) can call `$this->warpRecycleDatabase()` for a fresh committed state via a sub-second re-clone from golden.

How it works
------------

[](#how-it-works)

- **`WarmApplicationFactory`** boots the base app once per process and hands each test a shallow `clone` with fresh container/config anchors. The container's `bindings`/`instances`arrays are copied by value, so anything a test binds or resolves dies with its sandbox. Boot-resolved singletons shared by reference are handled by the manifest. The base's `db`manager is shared across sandboxes, keeping `RefreshDatabase`'s migrate-once + per-test transaction model intact.
- **`ResetManifest`** — the data-driven reset applied to every sandbox.
- **`HermeticitySentinel`** fingerprints env vars, the base config hash, and a static-probe registry after every test. If a test leaks shared state, the sentinel **fails that test**with attribution:

    ```
    [warp] hermeticity violation — this test leaked shared state: …

    ```

    A leak that corrupts the base scraps it, so the next test reboots pristine. This is the correctness backstop that lets warm mode stay honest.

Public API
----------

[](#public-api)

SymbolDescription`RawPHP\Warp\Concerns\InteractsWithWarmApplication`The trait host `TestCase`s use.`RawPHP\Warp\WarpMode::enabled(): bool``true` when `WARP_MODE` is `1`, `on`, or `true`.`RawPHP\Warp\Attributes\Isolated`Class attribute forcing a classic boot.`RawPHP\Warp\ResetManifest``default()` / `forget()` / `repoint()` / `flush()` / `add()`.`RawPHP\Warp\WarmApplicationFactory``sandbox()` / `base()` / `bootCount()` / `checkHermeticity()` / `scrap()`.`RawPHP\Warp\Sentinel\HermeticitySentinel`Post-test leak detector.`RawPHP\Warp\WarpMode::databaseEnabled(): bool``true` when `WARP_DB` is `1`, `on`, or `true`.`RawPHP\Warp\Db\SnapshotDatabaseManager``apply()` / `recycle()` / `shutdown()` — per-worker snapshot DB provisioning.Benchmarks
----------

[](#benchmarks)

The gate harness lives under `bench/`:

```
# Gate A — per-test framework tax (classic vs warm marginal ms/test):
bench/warm-tax.sh /path/to/your/app

# Gate B — outcome parity on a suite (classic vs warm junit diff):
bench/parity.sh /path/to/your/app tests/Feature/YourSuite

# Gate S2 — DB provisioning fixed cost (classic migrate vs snapshot clone):
bench/db-provision.sh /path/to/your/app
```

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

[](#development)

```
composer install
./vendor/bin/pest        # package suite (Unit classic + Feature warm)
```

Status
------

[](#status)

The warm-worker model is proven on real Laravel suites, from a few thousand tests up to large parallel runs. See the [gate report](docs/reports/2026-07-04-s1-gate.md) for full methodology and results.

###  Health Score

39

—

LowBetter than 84% of packages

Maintenance99

Actively maintained with recent releases

Popularity8

Limited adoption so far

Community2

Small or concentrated contributor base

Maturity40

Maturing project, gaining track record

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

Unknown

Total

1

Last Release

3d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/c66ee84d4063a7665c742b3965fc359e1908d02ecb93c54af32c7594d0b2f748?d=identicon)[rawphp](/maintainers/rawphp)

---

Tags

testingphpunitpestlaravelperformance

###  Code Quality

TestsPest

### Embed Badge

![Health badge](/badges/rawphp-warp/health.svg)

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

###  Alternatives

[code-distortion/adapt

A Laravel package that builds databases for your tests, improving their speed.

2838.1k](/packages/code-distortion-adapt)[mrpunyapal/rector-pest

Rector upgrade rules for Pest - refactoring and best practices for Pest testing framework

6977.7k63](/packages/mrpunyapal-rector-pest)[friendsofcake/fixturize

CakePHP Fixture classes to help increase productivity or performance

24520.3k1](/packages/friendsofcake-fixturize)[socialblue/laravel-query-adviser

With Laravel Query Adviser you can get more insights into the SQL queries created by Eloquent models used in your app. It logs the queries used by your application and provides a helpful overview of the SQL queries. You can rerun the SQL query to analyze the database impact or copy the SQL query to your clipboard. The handy card view allows you to quickly point out the pain points of your application's SQL queries.

203.8k](/packages/socialblue-laravel-query-adviser)

PHPackages © 2026

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