laragear/meta-testing

A Laravel Package helper for Laravel Packages

v3.1.0 2025-04-09 03:22 UTC

This package is auto-updated.

Last update: 2025-04-09 03:22:40 UTC


README

Latest Version on Packagist Latest stable test run Codecov coverage Maintainability Sonarcloud Status Laravel Octane Compatibility

A Laravel Package for testing Laravel Packages.

public function test_has_service_registered(): void
{
    $this->assertHasServices('my-cool-service');
}

Become a sponsor

Your support allows me to keep this package free, up-to-date and maintainable. Alternatively, you can spread the word on social media

Requirements

  • Laravel 11 or later.

Installation

Require this package into your project using Composer:

composer require --dev laragear/meta-testing

Caution

DO NOT install this package outside require-dev, unless you plan to use this package in production environments.

Testing

Testing the Service Provider

The InteractsWithServiceProvider allows to quickly test if the Service Provider of your package has registered all the needed bits of code into the Service Container.

use Orchestra\Testbench\TestCase
use Laragear\MetaTesting\InteractsWithServiceProvider;

class ServiceProviderTest extends TestCase
{
    use InteractsWithServiceProvider;
    
    public function test_is_registered_as_singleton(): void
    {
        $this->assertHasSingletons(\Vendor\Package\MyService::class);
    }
}

The available assertions are in this table:

Method Description
assertHasDriver() Assert a service as registered given driver name
assertHasServices() Assert services have been registered into the Service Container
assertHasSingletons() Assert services have been registered as a shared instance into the Service Container
assertHasNotSingletons() Assert services have been registered as a not-shared instance into the Service Container
assertConfigMerged() Assert the library configuration file has been merged into the application.
assertPublishes() Assert the library publishes the paths into the application
assertPublishesMigrations() Assert the library publishes the migrations into the application
assertHasTranslations() Assert the library translations have been registered into the translator
assertHasViews() Assert the library views have been registered into the view compiler
assertHasBladeComponent() Assert the library Blade Components have been registered into the view compiler
assertHasBladeDirectives() Assert the library Blade Directives have been registered into the view compiler
assertHasValidationRules() Assert the library Validation Rules have been registered into the validator
assertRouteByName() Assert the library Routes names have been registered into the router
assertRouteByUri() Assert the library Routes URIs have been registered into the router
assertRouteByAction() Assert the library Routes actions have been registered into the router
assertHasMiddlewareAlias() Assert the library Middleware alias has been registered into the router
assertHasGlobalMiddleware() Assert the library Middleware have been registered globally into the router
assertHasMiddlewareInGroup() Assert the library Middleware have been registered into a middleware group
assertGateHasAbility() Assert the library abilities have been registered into the authorization gate
assertGateHasPolicy() Assert the library policies have been registered into the authorization gate
assertHasScheduledTask() Assert the library scheduled tasks have been registered into the scheduler
assertScheduledTaskRunsAt() Assert the library scheduled tasks runs at a given moment
assertHasMacro() Assert the library macros are registered into the target Macroable class

Service Helpers

The InteractsWithServices trait includes helpers to retrieve services from the Service Container and do quick things like checks or preparation.

public function test_something_important(): void
{
    // Get a service from the Service Container, optionally run over a callback.
    $cache = $this->service('cache', fn ($cache) => $cache->set('foo', 'bar', 30));
    
    // Run a service once and forgets it, while running a callback over it.
    $compiler = $this->serviceOnce('blade.compiler', fn($compiler) => $compiler->check('cool'));
    
    // Executes a callback over a REAL service when already mocked.
    $this->unmock('files', function ($files): void {
        $files->copyDirectory('foo', 'bar');
    });
}

Validation

This meta package includes a InteractsWithValidator trait, that assert if a rule passes or fails using minimal data. This is useful when creating validation rules and testing them without too much boilerplate.

use Laragear\MetaTesting\Validation\InteractsWithValidator;

public function test_validation_rule(): void
{
    // Assert the validation rule passes.
    $this->assertValidationPasses(['test' => 'foo'],['test' => 'my_rule']);
    
    // Assert the validation rule fails.
    $this->assertValidationFails(['test' => 'bar'],['test' => 'my_rule']);
}

Middleware

You can test a middleware easily using the InteractsWithMiddleware trait and its middleware() method. It creates an on-demand route for the given path before sending a test Request to it, so there is no need to register a route.

use Illuminate\Http\Request;
use Vendor\Package\Http\Middleware\MyMiddleware;
use Laragear\MetaTesting\Http\Middleware\InteractsWithMiddleware;

public function test_middleware(): void
{
    $response = $this->middleware(MyMiddleware::class)->using(function (Request $request) {
        // ...
    })->post('test', ['foo' => 'bar']);
    
    $response->assertOk();
}

It proxies all MakesHttpRequest trait methods, like get() or withUnencryptedCookie(), so you can get creative with testing your middleware.

$this->middleware(MyMiddleware::class, 'test_argument')
    ->withUnencryptedCookie()
    ->be($this->myTestUser)
    ->post('test/route', ['foo' => 'bar'])
    ->assertSee('John');

Form Request

You can test a Form Request if it passes authorization a validation using different data using the InteractsWithFormRequests trait. The formRequest() requires the Form Request class, and an array with the data to include in the request, to test in isolation.

public function test_form_request()
{
    $this->formRequest(MyFormRequest::class, ['foo' => 'bar'])->assertOk();
}

Authorization

To check if a policy or gate works appropriately, use the InteractsWithAuthorization trait to check whether a user can or cannot be authorized to a given action.

public function test_authorization()
{
    $admin = User::factory()->admin()->create();
    
    $this->assertUserCan($admin, 'viewDashboard');
}

Casts

The InteractsWithCast trait allows to quickly test if a cast sets values from an attribute appropriately, and can return a given value from an attribute value. It also supports checking on multiple attributes at a time.

public function test_cast()
{
    $this->cast(MyTestCast::class)
        ->assertCastFrom(null, new Cast)
        ->assertCastTo('{"foo":"bar"}', new Cast(['foo' => 'bar']));
}

Pipeline

The InteractsWithPipeline trait allows to test and ensure pipes on the pipelines work as expected.

You may use this to test pipelines as a whole, ensuring the pipe order never changes, or test pipes in isolation by mocking services it requires to work. Alternatively, you may also mock the passable to test if some methods are called.

public function test_pipeline()
{
    $pipeline = $this->pipeline(MyPipeline::class)
        // Check the order of pipes
        ->assertPipes([
            FirstPipe::class,
            SecondPipe::class,
            ThirdPipe::class,
        ])
        // Check all pipes have their handler method.
        ->assertVia('handle');

    // Test the passable through all pipes and assert its result.         
    $pipeline->send(new Passable(['value' => 10]))
        ->assertPassable(function (Passable $passable) {
            return $passable->value === 130;
        })
        
    // Test a pipe in isolation and assert the results.
    $pipeline->isolatePipe(SecondClass::class)
        ->send(new Passable(['value' => 10]))
        ->assertPassable(function (Passable $passable) {
            return $passable->value === 100;
        });
        
    // Mock services a pipe or pipeline requires, or mock the passable. 
    $pipeline->isolatePipe(FirstPipe::class)
        ->withMockedService(MyService::class, function ($mock) {
            $mock->expects('sum')->with(0)->andReturn(10);
        })
        ->sendMock(Passable::class, function ($mock) {
            $mock->expects('set')->with(true)->andReturn(10);
        });
}

Laravel Octane compatibility

  • There are no singletons using a stale application instance.
  • There are no singletons using a stale config instance.
  • There are no singletons using a stale request instance.
  • There are no static properties being written.

There should be no problems using this package with Laravel Octane.

Security

If you discover any security related issues, please email darkghosthunter@gmail.com instead of using the issue tracker.

License

This specific package version is licensed under the terms of the MIT License, at time of publishing.

Laravel is a Trademark of Taylor Otwell. Copyright © 2011-2025 Laravel LLC.