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'));