Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/AlexanderDamont1/Stratus/llms.txt

Use this file to discover all available pages before exploring further.

Overview

Stratus POS uses PHPUnit 11 as its test runner, configured via phpunit.xml in the project root. Laravel Breeze ships with a suite of feature tests covering the full authentication flow.

Running tests

The recommended way to run the test suite is:
composer run test
This command:
  1. Clears the config cache with php artisan config:clear to ensure no stale configuration is used during tests
  2. Runs php artisan test, which wraps PHPUnit with Laravel-specific output formatting
You can also invoke PHPUnit directly:
./vendor/bin/phpunit

Test structure

tests/
├── Feature/      # Integration tests — test full HTTP requests, DB interactions, etc.
└── Unit/         # Unit tests — test individual classes and methods in isolation
SuiteDirectoryWhen to use
Featuretests/Feature/Test routes, controllers, middleware, and multi-layer interactions
Unittests/Unit/Test pure logic in models, services, or helpers in isolation
Prefer feature tests for most Stratus functionality. They give you higher confidence by exercising the full stack, and Laravel’s testing helpers make HTTP testing straightforward.

Running specific tests

Run a single test class:
php artisan test --filter ProfileTest
Run a single test method:
php artisan test --filter "ProfileTest::test_profile_information_can_be_updated"
Run all tests in a directory:
php artisan test tests/Feature/Auth
Run with verbose output:
php artisan test --verbose

Writing tests

Feature test example

Feature tests extend Tests\TestCase and can make HTTP requests against the application. The following example mirrors the actual profile test in the codebase (tests/Feature/ProfileTest.php):
tests/Feature/ProfileTest.php
<?php

namespace Tests\Feature;

use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class ProfileTest extends TestCase
{
    use RefreshDatabase;

    public function test_profile_information_can_be_updated(): void
    {
        $user = User::factory()->create();

        $response = $this
            ->actingAs($user)
            ->patch('/profile', [
                'name' => 'Test User',
                'email' => 'test@example.com',
            ]);

        $response
            ->assertSessionHasNoErrors()
            ->assertRedirect('/profile');

        $user->refresh();

        $this->assertSame('Test User', $user->name);
        $this->assertSame('test@example.com', $user->email);
        $this->assertNull($user->email_verified_at);
    }
}

Unit test example

tests/Unit/UserTest.php
<?php

namespace Tests\Unit;

use App\Models\User;
use PHPUnit\Framework\TestCase;

class UserTest extends TestCase
{
    public function test_password_is_hidden_from_serialization(): void
    {
        $user = new User(['password' => 'secret']);

        $this->assertArrayNotHasKey('password', $user->toArray());
    }
}

Using factories

The User model ships with UserFactory via the HasFactory trait. Use it to generate test users:
use App\Models\User;

// Basic user
$user = User::factory()->create();

// User with specific attributes
$user = User::factory()->create([
    'email' => 'test@example.com',
]);

// Unverified user (email_verified_at is null)
$user = User::factory()->unverified()->create();

// User that is not persisted to the database
$user = User::factory()->make();

// Multiple users
$users = User::factory()->count(10)->create();
Tests that write to the database should use the RefreshDatabase trait. This wraps each test in a transaction that is rolled back on completion, keeping tests isolated.

Using Faker

Faker is available in factories and tests for generating realistic fake data.
use Faker\Factory as Faker;

$faker = Faker::create();

$email = $faker->unique()->safeEmail(); // e.g. john.doe@example.org
$name  = $faker->name();                // e.g. Jane Smith
$price = $faker->randomFloat(2, 1, 999); // e.g. 42.50
In a factory, Faker is already available via $this->faker:
database/factories/UserFactory.php
public function definition(): array
{
    return [
        'name'              => fake()->name(),
        'email'             => fake()->unique()->safeEmail(),
        'email_verified_at' => now(),
        'password'          => static::$password ??= Hash::make('password'),
        'remember_token'    => Str::random(10),
    ];
}

/**
 * Indicate that the model's email address should be unverified.
 */
public function unverified(): static
{
    return $this->state(fn (array $attributes) => [
        'email_verified_at' => null,
    ]);
}

Mocking with Mockery

Mockery is included for mocking dependencies in unit tests.
use Mockery;

$mock = Mockery::mock(PaymentGateway::class);
$mock->shouldReceive('charge')
    ->once()
    ->with(1000)
    ->andReturn(true);

// Bind the mock into the service container
$this->app->instance(PaymentGateway::class, $mock);
Laravel also has first-class support for mocking via $this->mock():
$this->mock(PaymentGateway::class, function (MockInterface $mock) {
    $mock->shouldReceive('charge')->once()->andReturn(true);
});
For facades (e.g. Mail, Event, Queue), prefer Laravel’s built-in fake helpers over Mockery:
Mail::fake();
Event::fake();
Queue::fake();

Code coverage

Generate an HTML coverage report (requires Xdebug or PCOV):
php artisan test --coverage
Output a coverage report to a directory:
php artisan test --coverage-html coverage/
Enforce a minimum coverage threshold:
php artisan test --coverage --min=80
Code coverage requires either the Xdebug or PCOV PHP extension. PCOV is significantly faster for coverage collection and is recommended for CI environments.

Build docs developers (and LLMs) love