Skip to main content

Using Pest

This guide documents the testing helpers, conventions, and setup practices used for writing expressive tests with Pest.

If you have never used Pest make sure to read the Pest documentation first, make sure to at least fully read the following pages.

If you have never tested with Laravel, it is also recommended to carefully read the Laravel documentation. Laravel already includes helpers for most situations.

warning

Links are for Laravel 12.x, make sure to select the appropriate version.

Tenancy Initialization​

public function tenancyInitialize(int $id = 1): void
{
tenancy()->initialize($id);
$this->beginDatabaseTransaction();
}

Use this method in beforeEach to:

  • Boot the tenant environment using tenancy()->initialize($id)
  • Begin a database transaction to isolate changes per test

Example​

beforeEach(function () {
$this->tenancyInitialize(); // Defaults to tenant ID 1
});

Booting Extensions​

If your app includes extensions (modules, plugins) and they are needed for the test, boot them using:

boot_extensions();

Example​

beforeEach(function () {
$this->tenancyInitialize();
boot_extensions();
});

This ensures everything is registered and ready during the test.

User & Auth Helpers​

use Qore\System\Models\Central\User;

function user(int $tenantId = 1): User
function admin(): User
function actingAsUser(int $tenantId = 1): User
function actingAsAdmin(): User
  • user() – Creates a new user for a given tenant
  • admin() – Retrieves the first seeded user
  • actingAsUser() – Creates a new user for a given tenant and authenticates the user
  • actingAsAdmin() – Authenticates as an admin user

Example​

actingAsUser();
actingAsAdmin();

Permission Test Helpers​

permissionHttpStates()​

function permissionHttpStates(string $permission, int $with = 200, int $without = 403): array

Generates test cases with/without the given permission and expected HTTP statuses.

Example​

it('can index resources', function (User $user, int $status) {
indexResource(MyResource::class)->assertStatus($status);
})->with(permissionHttpStates('view resources'));

permissionBoolStates()​

function permissionBoolStates(string $permission, bool $with = true, bool $without = false): array

Returns true/false states to assert business logic instead of HTTP response codes.

Example​

it('can run a resource action', function (User $user, bool $can) {
$action = resourceAction(MyResource::class, SomeAction::class);

expect($action->checkCanRun($model))->toBe($can);
})->with(permissionBoolStates('run action'));

statusOk()​

function statusOk(int $status): bool

Shorthand to check if a response is OK (200). Used to prevent further assertions in unauthorized cases.

Resource Helpers​

indexResource()​

use Illuminate\Testing\TestResponse;

function indexResource(string $resource): TestResponse

showResource()​

use Illuminate\Testing\TestResponse;
use Illuminate\Database\Eloquent\Model;

function showResource(string $resource, Model $model): TestResponse

Example​

use Qore\System\Models\Central\User;
use Qore\System\Mailing\Models\Tenant\MailTemplate;
use Qore\System\Mailing\Resources\MailTemplateResource;

it('can show mail template', function (User $user, int $status) {
$template = MailTemplate::query()->first();

$response = showResource(MailTemplateResource::class, $template)
->assertStatus($status);

if (! statusOk($status)) return;

$response->assertJsonPath('values', [
'name' => 'Forgot password',
'subject' => 'New password',
'attachments' => [],
'driver' => 'SMTP',
'sender_name' => 'Bedrijf (Qlic)',
'sender_email_address' => 'Bedrijf (info@qlic.nl)',
'mail_footer' => 'Bedrijf',
'cc' => null,
'bcc' => null,
'content' => $template->content,
'variable_list' => 'Wachtwoord vergeten',
'layout_name' => 'clean',
]);

$response->assertJsonPath('model', [
'id' => 1,
'title' => 'Forgot password',
'description' => null,
]);
})->with(permissionHttpStates('mail management'));

createResource()​

use Illuminate\Testing\TestResponse;

function createResource(string $resource, array $data): TestResponse

Example​

use Qore\System\Models\Central\User;
use Qore\System\Mailing\Resources\MailTemplateResource;

it('can create mail template', function (User $user, int $status) {
createResource(MailTemplateResource::class, [
'name' => fake()->name,
'subject' => fake()->sentence,
'driver' => fake()->randomElement(['smtp', 'log']),
'sender_name' => ['value' => fake()->name],
'sender_email_address' => ['value' => fake()->email],
'content' => fake()->paragraph,
])
->assertStatus($status);
})->with(permissionHttpStates('mail template management'));

updateResource()​

use Illuminate\Testing\TestResponse;
use Illuminate\Database\Eloquent\Model;

function updateResource(string $resource, Model $model, array $data): TestResponse

Example​

use Qore\System\Models\Central\User;
use Qore\System\Mailing\Models\Tenant\MailTemplate;
use Qore\System\Mailing\Resources\MailTemplateResource;

it('can update mail template', function (User $user, int $status) {
$mailTemplate = MailTemplate::query()->first();

updateResource(MailTemplateResource::class, $mailTemplate, [
'name' => fake()->name,
'subject' => fake()->sentence,
'driver' => fake()->randomElement(['smtp', 'log']),
'sender_name' => [
'value' => fake()->name,
],
'sender_email_address' => [
'value' => fake()->email,
],
'content' => fake()->paragraph,
])
->assertStatus($status);
})->with(permissionHttpStates('mail management'));

deleteResource()​

use Illuminate\Testing\TestResponse;
use Illuminate\Database\Eloquent\Model;

function deleteResource(string $resource, Model $model): TestResponse

Example​

use Qore\System\Models\Central\User;
use Qore\System\Mailing\Models\Tenant\MailTemplate;
use Qore\System\Mailing\Resources\MailTemplateResource;

it('can delete mail template', function (User $user, int $status) {
$template = MailTemplate::query()->first();

deleteResource(MailTemplateResource::class, $template)
->assertStatus($status);
})->with(permissionHttpStates('mail management', withPermissionStatus: 403));

resourceAction()​

use Qore\System\Resource\Action\Action;

function resourceAction(string $resource, string $action): Action

Example Action Visibility​

use Qore\System\Models\Central\User;
use Qore\System\Mailing\Models\Tenant\MailTemplate;
use Qore\System\Mailing\Resources\MailTemplateResource;
use Qore\System\Mailing\Http\Actions\SendTestMessageFromTemplate;

it('can see and run SendTestMessageFromTemplate action', function (User $user, bool $can) {
$template = MailTemplate::query()->first();
$action = resourceAction(MailTemplateResource::class, SendTestMessageFromTemplate::class);

expect($action)
->checkCanSee()->toBe($can)
->checkCanRun($template)->toBe($can);
})->with(permissionBoolStates('mail management'));

Example Action Execution​

use Illuminate\Support\Facades\Mail;
use Qore\System\Mailing\Models\Tenant\MailTemplate;
use Qore\System\Mailing\Mail\LaravelMail;
use Qore\System\Mailing\Resources\MailTemplateResource;
use Qore\System\Mailing\Http\Actions\SendTestMessageFromTemplate;

it('sends message from mail template', function () {
Mail::fake();
$template = MailTemplate::query()->first();
$action = resourceAction(MailTemplateResource::class, SendTestMessageFromTemplate::class);

$action->run($template, [
'to' => $to = fake()->email,
]);

Mail::assertSent(LaravelMail::class, function (LaravelMail $mail) use ($to) {
expect($mail->to)->toBe([[
'name' => null,
'address' => $to,
]]);

return true;
});
})->with(permissionBoolStates('mail management'));

resourceAlert()​

use Qore\System\Resource\Alert\Alert;

function resourceAlert(string $resource, string $alert): Alert

Example​

use Qore\System\Mailing\Models\Tenant\MailTemplate;
use Qore\System\Mailing\Resources\MailTemplateResource;
use Qore\System\Mailing\Alerts\MailTemplateLocked;

it('shows alert when template is locked', function (bool $locked) {
$template = MailTemplate::query()->first();
$template->locked_at = $locked ? now() : null;
$template->save();

$alert = resourceAlert(MailTemplateResource::class, MailTemplateLocked::class);

expect($alert->isShownOnDetailViaClosure($template))->toBe($locked);
})->with([
'locked' => true,
'unlocked' => false,
]);

Examples​

Resource Index​

use Qore\System\Models\Central\User;
use Qore\System\Mailing\Resources\MailTemplateResource;

it('can index mail templates', function (User $user, int $status) {
$response = indexResource(MailTemplateResource::class)
->assertStatus($status);

if (! statusOk($status)) return;

$response->assertJsonPath('pagination.data', [
[
'id' => 1,
'name' => 'Forgot password',
'subject' => 'New password',
'variable_list' => 'Wachtwoord vergeten',
],
[
'id' => 2,
'name' => 'Password is reset',
'subject' => 'Your password is reset',
'variable_list' => 'Wachtwoord is gereset',
],
]);
})->with(permissionHttpStates('mail template management'));

Resource Creation​

use Qore\System\Models\Central\User;
use Qore\System\Mailing\Resources\MailTemplateResource;

it('can create mail template', function (User $user, int $status) {
createResource(MailTemplateResource::class, [
'name' => fake()->name,
'subject' => fake()->sentence,
'driver' => fake()->randomElement(['smtp', 'log']),
'sender_name' => ['value' => fake()->name],
'sender_email_address' => ['value' => fake()->email],
'content' => fake()->paragraph,
])
->assertStatus($status);
})->with(permissionHttpStates('mail template management'));