PHPackages                             builtbyberry/laravel-swarm-installer-testkit - 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. builtbyberry/laravel-swarm-installer-testkit

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

builtbyberry/laravel-swarm-installer-testkit
============================================

Shared Testbench-based test harness for `swarm:install\*` command test suites across Laravel Swarm and its companion packages.

v0.1.2(2d ago)0341↑1043.7%1MITPHPPHP ^8.5CI passing

Since Jul 6Pushed 2d agoCompare

[ Source](https://github.com/builtbyberry/laravel-swarm-installer-testkit)[ Packagist](https://packagist.org/packages/builtbyberry/laravel-swarm-installer-testkit)[ RSS](/packages/builtbyberry-laravel-swarm-installer-testkit/feed)WikiDiscussions main Synced today

READMEChangelog (2)Dependencies (8)Versions (5)Used By (1)

Laravel Swarm Installer Testkit
===============================

[](#laravel-swarm-installer-testkit)

Shared Testbench-based test harness for `:install*` Artisan command test suites. Extracted from `builtbyberry/laravel-swarm` so companion packages (`builtbyberry/laravel-swarm-pulse` and others) can `require-dev`it directly instead of duplicating the harness.

This package is `require-dev`-only. It requires `orchestra/testbench`directly (rather than through a consumer's own `require-dev`) since testing Artisan installer commands is this package's entire purpose.

What you get
------------

[](#what-you-get)

`InstallerTestCase` is the base test case. Extend it via a small package subclass that supplies your service providers:

```
namespace App\Tests\Installer;

use BuiltByBerry\LaravelSwarmInstallerTestkit\InstallerTestCase;

class MyPackageInstallerTestCase extends InstallerTestCase
{
    protected function getPackageProviders($app): array
    {
        return [
            \My\Package\MyPackageServiceProvider::class,
        ];
    }
}
```

Then bind it per test file via the standard Pest `uses()` call:

```
use App\Tests\Installer\MyPackageInstallerTestCase;

uses(MyPackageInstallerTestCase::class);
```

On `setUp()` the harness:

1. Spins up an Orchestra Testbench application booting the providers your subclass declares.
2. Materializes a temp directory shaped like a freshly-scaffolded Laravel 13 app — `config/`, `routes/console.php`, `app/Providers/AppServiceProvider.php`, `.env`, `composer.json`, plus the usual `database/`, `resources/`, `storage/`, `bootstrap/`, `public/`, `tests/` directories.
3. Re-points the running application at the scratch skeleton via `$this->app->setBasePath(...)` so `app_path()`, `config_path()`, `base_path()`, `database_path()`, etc. all resolve into the fixture.
4. Tears the temp directory down in `tearDown()`. Each test gets its own uniquely-named skeleton — tests are parallel-safe.

Writing an installer test
-------------------------

[](#writing-an-installer-test)

```
use App\Tests\Installer\MyPackageInstallerTestCase;

uses(MyPackageInstallerTestCase::class);

test('my:install wires up the runtime', function () {
    $this->runInstaller('my:install')
        ->assertSucceeded()
        ->assertOutputContains('Installed.');

    $this->assertFileContains('config/my-package.php', "'driver' => 'database'");
    $this->assertEnvKey('MY_PACKAGE_DRIVER', 'database');
    $this->assertScheduleEntry('my:prune');
});
```

### Idempotency

[](#idempotency)

Every installer should be safe to re-run. The harness has a one-liner:

```
test('my:install is idempotent', function () {
    $this->runInstaller('my:install')
        ->assertSucceeded()
        ->twice()
        ->assertSecondRunIsNoOp();
});
```

`twice()` runs the installer a second time with the same arguments and returns a `DoubleRunResult`. `assertSecondRunIsNoOp()` then verifies:

- the second run exited 0
- no file was created
- no file was deleted
- no file's contents (sha256) changed

If your installer needs to be re-runnable but has a `--force` flag that intentionally overwrites, test `--force` separately — `assertSecondRunIsNoOp()`is only for the default-mode contract.

### Refusal paths

[](#refusal-paths)

Every installer should fail loudly when its preconditions are violated (unsupported driver, already-installed-and-modified, missing `--force`, etc.). The refusal helper checks both exit code and error message in one call:

```
test('my:install refuses on an unsupported driver', function () {
    $this->writeSkeletonFile('config/my-package.php', "
