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.
Links are for Laravel 12.x, make sure to select the appropriate version.
- HTTP Tests
- Database Testing
- Mocking //: # (context-remember)
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 tenantadmin()
– Retrieves the first seeded useractingAsUser()
– Creates a new user for a given tenant and authenticates the useractingAsAdmin()
– 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'));