Search by

dejwcake / testing-kit

dejwCake

Testing utilities and base test cases for Craftable/Laravel projects

Package info

github.com/dejwCake/testing-kit

pkg:composer/dejwcake/testing-kit

Statistics

Installs: 479

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 0

1.3.0 2026-10-18 21:07 UTC

This package is auto-updated.

Last update: 2026-11-02 10:26:45 UTC


README

Testing Kit is a Laravel package that provides reusable testing infrastructure for Craftable-based projects. It supplies:

  • A TestCase base (database refresh, translator mocking, dummy CSRF, snapshot helpers, download assertions, declarative actor resolution from PHP attributes)
  • HttpTestCase, WebTestCase, ApiTestCase for HTTP / web / API integration tests
  • Context PHP attribute for declarative customer | admin-user | anonymous setup per test method or class
  • UserFactory and AdminUserFactory with the underlying model class pluggable via config (constructor-injected Hasher); AdminUserFactory also assigns the configured admin role
  • HTML snapshot driver and SnapshotAsserts trait for view snapshot testing
  • OpenApiValidationTrait and helper Util for asserting responses against an OpenAPI spec

This package is part of Craftable (dejwCake/craftable), an administration starter kit for Laravel.

Install

Add the path repository (or a Packagist version) and require as a dev dependency in your application:

"require-dev": {
    "dejwcake/testing-kit": "*"
}

The TestingKitServiceProvider is auto-discovered by Laravel.

Publish the config (optional) to override the user models, default emails, role name, or the OpenAPI spec path:

php artisan vendor:publish --tag=testing-kit-config

Config

config/testing-kit.php (after publishing):

Key Default Purpose
user_model App\Models\User Model class used by UserFactory
admin_user_model Brackets\AdminAuth\Models\AdminUser Model class used by AdminUserFactory
authenticated_user_id 123 Default id used by actingAsCustomer() / actingAsAdminUser() when none is passed
dummy_csrf_token 'csrf-token-mock' Token put into the test session
default_locale 'en' Locale set in createApplication()
default_user_email 'test@example.com' Email pinned on customer fixtures
default_admin_user_email 'admin@example.com' Email pinned on admin user fixtures
default_admin_role 'Administrator' Role assigned to admin user fixtures via Spatie HasRoles
openapi.spec_path storage_path('api-docs/openapi.json') Spec file used by ApiTestCase
openapi.regenerate_command 'l5-swagger:generate' Artisan command to regenerate the spec
openapi.regenerate_on_init true Whether ApiTestCase::setUp regenerates the spec

Usage

Web test (HTML snapshot + download assertion)

use DejwCake\TestingKit\Functional\WebTestCase;
use DejwCake\TestingKit\Attributes\Context;

final class InstructionsControllerTest extends WebTestCase
{
    #[Context(user: 'customer')]
    public function testCustomerCanDownloadInstruction(): void
    {
        $response = $this->get(route('web/instructions/show', ['legoSet' => 5]));

        $response->assertOk();
        $this->assertDownload($response, 'dummy.pdf');
    }
}

API test (OpenAPI validation)

use DejwCake\TestingKit\Functional\ApiTestCase;
use DejwCake\TestingKit\Attributes\Context;

final class PostsControllerTest extends ApiTestCase
{
    #[Context(user: 'customer')]
    public function testCustomerCanListPosts(): void
    {
        $response = $this->getJson(route('api/posts/index'));

        $response->assertOk();
        $this->assertValidOpenApiResponseForRoute('GET', 'api/posts/index', $response);
    }
}

Acting as an admin

#[Context(user: 'admin-user')] resolves the guard from admin-auth.defaults.guard (Spatie HasRoles then sees the admin guard, so the role lookup matches the admin-auth installation migration). The fixture admin user has id = testing-kit.authenticated_user_id.

Translations in tests

Every base TestCase mocks the translator, so trans() and __() return the key and apply no replacements. That is deliberate: a suite should assert on functionality, not on what a translation file currently says, and stable keys are what keep snapshots readable when copy changes.

The trade-off is that a placeholder mistake is invisible — :nam instead of :name, or a replacement key that does not match the line, renders exactly like a correct one, so nothing fails. When the interpolation is what you are testing, opt out for that test:

public function testTheMessageFillsInEveryPlaceholder(): void
{
    $this->useRealTranslator();

    $rendered = $this->app->make(ViewFactory::class)->make('mail.welcome', ['name' => 'Ada'])->render();

    self::assertStringNotContainsString(':name', $rendered);
    self::assertStringContainsString('Ada', $rendered);
}

It applies for the rest of that test only; the next one gets the mock back. Keep asserting on values the test supplies rather than on the contents of a translation file, or you are back to tests that fail when someone rewords a sentence.

The validator is rebuilt alongside the translator, so validation messages come from the same place — without that, a test could render real messages while $validator->errors() still returned validation.* keys.

Issues

If something is not working as expected, please open an issue in the main repository https://github.com/dejwCake/craftable.

How to develop this project

Composer

Update dependencies:

docker compose run -it --rm test composer update

Composer normalization:

docker compose run -it --rm php-qa composer normalize

Run code analysis tools (php-qa)

PHP compatibility:

docker compose run -it --rm php-qa phpcs --standard=.phpcs.compatibility.xml --cache=.phpcs.cache

Code style:

docker compose run -it --rm php-qa phpcs -s --colors --extensions=php

Fix style issues:

docker compose run -it --rm php-qa phpcbf -s --colors --extensions=php

Static analysis (phpstan):

docker compose run -it --rm php-qa phpstan analyse --configuration=phpstan.neon

Regenerate the phpstan baseline:

docker compose run -it --rm php-qa phpstan analyse --configuration=phpstan.neon --generate-baseline=phpstan-baseline.neon

Mess detector (phpmd):

docker compose run -it --rm php-qa phpmd analyze

Regenerate the phpmd baseline:

docker compose run -it --rm php-qa phpmd analyze --generate-baseline

Run tests

Run tests:

docker compose run -it --rm test ./vendor/bin/phpunit

Run tests with coverage:

docker compose run -it --rm test ./vendor/bin/phpunit --coverage-text

To regenerate snapshots use:

docker compose run -it --rm -e UPDATE_SNAPSHOTS=true test ./vendor/bin/phpunit

Run the whole PHP suite

Run every PHP check and the test suite in sequence (stops at the first failure):

docker compose run -it --rm test composer update \
  && docker compose run -it --rm php-qa composer normalize \
  && docker compose run -it --rm php-qa phpcs --standard=.phpcs.compatibility.xml --cache=.phpcs.cache \
  && docker compose run -it --rm php-qa phpcs -s --colors --extensions=php \
  && docker compose run -it --rm php-qa phpstan analyse --configuration=phpstan.neon \
  && docker compose run -it --rm php-qa phpmd analyze \
  && docker compose run -it --rm test ./vendor/bin/phpunit