Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Swarm Installer Testkit Laravel Package

builtbyberry/laravel-swarm-installer-testkit

A testing toolkit for the Laravel Swarm installer, providing helpers and fixtures to verify installation flows, file scaffolding, and command behavior in your test suite with confidence.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a dev-only package. It ships no runtime code and should never appear in require. Its job is to give every package in the Swarm family (core laravel-swarm plus companions) the same Orchestra Testbench scaffolding for testing swarm:install* Artisan commands, so an installer test written in one repo looks and behaves like the same test in another.

Install it:

composer require --dev builtbyberry/laravel-swarm-installer-testkit

Then check two things in composer.json before writing a line of test code:

  1. The require-dev block of the testkit itself — the Testbench major version it pins must match the Laravel version you support. Testbench majors are tightly coupled to Laravel majors, and a mismatch produces confusing "class not found" or container errors rather than a clean failure.
  2. phpunit.xml.dist / pest.php — your suite must point at the harness base class, not Orchestra\Testbench\TestCase directly, or you'll silently lose every helper the package provides.

Where to look first:

  • src/ for the base TestCase and any traits (typically something like InteractsWithSwarmInstaller or InstallerAssertions).
  • Any stubs/ or fixtures/ directory — this is where the sandbox skeleton app and canned installer output live.
  • The package's own tests/ directory. A test harness is best documented by its self-test; the testkit's own suite is the working example of every helper it exposes.

First use case: prove that php artisan swarm:install publishes a config file and registers the service provider without shelling out to Composer or writing into your real vendor/ or config/ directories. Something like:

use BuiltByBerry\SwarmInstallerTestkit\TestCase;

final class InstallCommandTest extends TestCase
{
    public function test_it_publishes_config(): void
    {
        $this->artisan('swarm:install', ['--no-interaction' => true])
            ->assertExitCode(0);

        $this->assertFileExists(config_path('swarm.php'));
    }
}

Names above follow the conventions this style of harness uses — confirm the exact base class namespace and helper names against src/ on first install, since at 0 stars there's no ecosystem of blog posts to fall back on.

Implementation Patterns

Wire the harness in once, per package. Create a thin tests/TestCase.php that extends the testkit base and declares your provider. Every installer test then extends that, giving you one place to bump when Testbench majors change:

namespace BuiltByBerry\Swarm\Tests;

use BuiltByBerry\SwarmInstallerTestkit\TestCase as InstallerTestCase;

abstract class TestCase extends InstallerTestCase
{
    protected function getPackageProviders($app): array
    {
        return [\BuiltByBerry\Swarm\SwarmServiceProvider::class];
    }
}

For Pest, bind it globally instead: uses(Tests\TestCase::class)->in('Feature/Install').

Fake the process layer, always. Installer commands are wrappers around composer require, npm install, and php artisan vendor:publish. The single most valuable thing this harness buys you is a consistent way to intercept those calls (Laravel's Process::fake() or an equivalent binding) so tests are hermetic and fast. Set the fake in setUp() before the command runs, and assert on the recorded invocations rather than just the exit code — "exit 0 but ran composer require against the live network" is the failure mode you're guarding against.

Drive flags through data providers. Installers exist to handle permutations: --force over an existing config, --no-interaction in CI, re-running when already installed, missing optional dependencies. A provider over [flags, preconditions, expected artifacts] keeps the matrix readable and is the natural shape for this harness:

#[DataProvider('flagMatrix')]
public function test_install_respects_flags(array $flags, array $expectedFiles): void { /* ... */ }

Reuse the same harness across the family. The whole point of the package is that laravel-swarm, swarm-queue, swarm-tenancy, etc. all assert installation the same way. Keep your per-package TestCase a pure declaration (providers + fixtures) and push any shared custom assertion into the testkit itself via a PR, or into a local trait if it's genuinely package-specific. Resist copy-pasting assertion helpers between repos — that's the drift this package exists to prevent.

Version the testkit in lockstep with the installer. Because the harness encodes assumptions about what swarm:install produces (config keys, migration names, published tag names), treat a bump of the install command and a bump of the testkit as one atomic change across repos. A composer update in one companion repo that pulls a newer testkit than its siblings is the most likely source of "works in core, red in companion" CI noise.

Add a CI matrix job that runs the suite against each supported Laravel version. Testbench makes this cheap (ORCHESTRA_TESTBENCH / laravel/framework constraint per job), and installer commands are exactly the kind of code that breaks on framework majors due to signature changes in Process, Filesystem, and the Command lifecycle.

Gotchas and Tips

  • Release metadata is odd — pin it. A 2026-09-03 release date with 0 stars and 0 dependents means you are effectively the first consumer. Use an explicit version constraint or a commit SHA in require-dev, and vendor/fork if the repo goes quiet; there's no community to notice a break.
  • --no-interaction is mandatory. Installer commands love $this->confirm(). Without -n (or the array equivalent ['--no-interaction' => true]), tests hang in CI until the job timeout rather than failing with a useful message.
  • Register process fakes before the application boots if anything in your provider resolves Process in a singleton or bootstrapping callback. A fake set in the test body arrives too late and the real binary runs.
  • Testbench sandbox paths are ephemeral but not isolated. Files written to config_path() or base_path() inside the sandbox persist for the life of the process unless you reset them. Clean up in tearDown() (or override the harness's reset hook) or a later test in the same class will see artifacts from an earlier one and produce order-dependent green/red.
  • File::fake() doesn't help here. It fakes the storage disks, not real paths an installer writes to. Use the sandbox's actual temp directory and assert on real file_exists()/file_get_contents().
  • Clear compiled caches between tests. Published configs, bootstrap/cache/*, and the vendor manifest can be cached from a previous test's install run, making a "fresh install" test pass for the wrong reason.
  • Watch for Composer scripts. If your sandbox app's composer.json carries post-autoload-dump hooks, faking the process layer may not stop them from firing during bootstrapping. Keep the sandbox composer.json minimal.
  • Debugging: dump the full command output with ->dump() (or ->expectsOutputToContain(...)) inside $this->artisan(...) when an assertion on published files fails but the exit code is 0 — installers commonly swallow exceptions and report success.
  • Extension points: the usual overrides are defineEnvironment() (env/config for the sandbox), getPackageProviders(), and the fixture/sandbox-path accessor. If you find yourself overriding more than two or three methods, you're fighting the harness — check whether a testkit PR would be the better fix.
  • Don't test the testkit. Assertions about the harness's own behaviour belong upstream. In your package, assert artifacts (files, migrations, registered bindings, process invocations) and keep at least one assertion tied to observable output, so a harness regression surfaces as a real failure rather than a silently weakened test.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jinas/dhivatar
store-doc/laravel-storage-driver
plus-it/laravel-translation-manager
diephp/perhaps
diephp/telegraph
osmaviation/spreadsheet
microsoft/fluentui-system-icons
mmccook/php-json-canonicalization-scheme
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
cgv/localized-resource