Documentation Index
Fetch the complete documentation index at: https://mintlify.com/Arthurr23/XHealtXperience/llms.txt
Use this file to discover all available pages before exploring further.
XHealtXperience ships with a PHPUnit 11 test suite targeting the central authentication, user-profile flows, and basic application health. Tests run against an in-memory SQLite database so they are fast, hermetic, and require no changes to your local .env file. This page explains the configuration, describes every test class, and shows you how to run the suite.
Test configuration (phpunit.xml)
The phpunit.xml at the project root configures two test suites and a set of environment overrides that isolate the test run from your local services:
<testsuites>
<testsuite name="Unit">
<directory>tests/Unit</directory>
</testsuite>
<testsuite name="Feature">
<directory>tests/Feature</directory>
</testsuite>
</testsuites>
Environment overrides
| Variable | Test value | Why |
|---|
APP_ENV | testing | Activates Laravel’s testing mode. |
DB_CONNECTION | sqlite | Uses SQLite instead of your local DB. |
DB_DATABASE | :memory: | Every test run starts with a blank in-memory database — no file cleanup needed. |
CACHE_STORE | array | In-process array cache; no Redis/database needed. |
QUEUE_CONNECTION | sync | Jobs run synchronously in the same process — no queue worker required. |
SESSION_DRIVER | array | In-process session store; no database write required. |
MAIL_MAILER | array | Outgoing mail is captured in memory for assertion, never sent. |
BCRYPT_ROUNDS | 4 | Minimum bcrypt cost — makes User::factory() calls dramatically faster. |
BROADCAST_CONNECTION | null | Disables broadcasting. |
Running the test suite
Clear the configuration cache
Stale cached config can cause unexpected failures in the testing environment. The composer run test script does this automatically, but you can also do it manually:
The recommended way to execute the full suite:
php artisan config:clear --ansi
php artisan test
Alternatively, invoke PHPUnit directly
PHPUnit outputs a colour-coded summary. A passing run looks like:
PASS Tests\Unit\ExampleTest
PASS Tests\Feature\ExampleTest
PASS Tests\Feature\Auth\AuthenticationTest
PASS Tests\Feature\Auth\EmailVerificationTest
PASS Tests\Feature\Auth\PasswordConfirmationTest
PASS Tests\Feature\Auth\PasswordResetTest
PASS Tests\Feature\Auth\PasswordUpdateTest
PASS Tests\Feature\Auth\RegistrationTest
PASS Tests\Feature\ProfileTest
Use the --filter flag to run a single test method or class without executing the entire suite:# Run one test class
php artisan test --filter=AuthenticationTest
# Run a single test method
php artisan test --filter=test_users_can_authenticate_using_the_login_screen
# Run only the Feature suite
php artisan test --testsuite=Feature
Test inventory
Unit tests — tests/Unit/
| File | Tests |
|---|
ExampleTest.php | Sanity check — asserts that true === true. Serves as a placeholder for future unit tests. |
Feature tests — tests/Feature/
All feature tests that use the RefreshDatabase trait wrap each test in a transaction (or re-migrate the in-memory SQLite DB) so tests never bleed state into one another.
ExampleTest.php
Basic application health check.
| Test method | What it asserts |
|---|
test_the_application_returns_a_successful_response | GET / returns HTTP 200, confirming the application boots and routes correctly. |
Auth/AuthenticationTest.php
Tests the central login and logout flow.
| Test method | What it asserts |
|---|
test_login_screen_can_be_rendered | GET /login returns HTTP 200. |
test_users_can_authenticate_using_the_login_screen | POST /login with valid credentials authenticates the user and redirects to dashboard. |
test_users_can_not_authenticate_with_invalid_password | POST /login with a wrong password leaves the user as a guest. |
test_users_can_logout | POST /logout while authenticated de-authenticates and redirects to /. |
Auth/RegistrationTest.php
Tests the central user registration screen.
| Test method | What it asserts |
|---|
test_registration_screen_can_be_rendered | GET /register returns HTTP 200. |
test_new_users_can_register | POST /register with valid data authenticates the new user and redirects to dashboard. |
Auth/PasswordResetTest.php
Tests the full password-reset flow using Notification::fake().
| Test method | What it asserts |
|---|
test_reset_password_link_screen_can_be_rendered | GET /forgot-password returns HTTP 200. |
test_reset_password_link_can_be_requested | POST /forgot-password dispatches a ResetPassword notification to the user. |
test_reset_password_screen_can_be_rendered | GET /reset-password/{token} (from the notification) returns HTTP 200. |
test_password_can_be_reset_with_valid_token | POST /reset-password with a valid token sets the new password and redirects to /login. |
Auth/PasswordUpdateTest.php
Tests updating a user’s own password from the profile page.
| Test method | What it asserts |
|---|
test_password_can_be_updated | PUT /password with the correct current password updates the hash and redirects to /profile. |
test_correct_password_must_be_provided_to_update_password | PUT /password with a wrong current password returns a current_password validation error. |
Auth/PasswordConfirmationTest.php
Tests the password-confirmation gate used before sensitive actions.
| Test method | What it asserts |
|---|
test_confirm_password_screen_can_be_rendered | GET /confirm-password returns HTTP 200 for an authenticated user. |
test_password_can_be_confirmed | POST /confirm-password with the correct password redirects without session errors. |
test_password_is_not_confirmed_with_invalid_password | POST /confirm-password with a wrong password returns session errors. |
Auth/EmailVerificationTest.php
Tests the email-verification flow using Event::fake() and temporary signed URLs.
| Test method | What it asserts |
|---|
test_email_verification_screen_can_be_rendered | GET /verify-email returns HTTP 200 for an unverified user. |
test_email_can_be_verified | Navigating to a valid signed verification URL dispatches the Verified event and marks the user’s email as verified; redirects to dashboard?verified=1. |
test_email_is_not_verified_with_invalid_hash | A signed URL with a wrong hash does not verify the email. |
ProfileTest.php
Tests profile viewing, updating, and account deletion.
| Test method | What it asserts |
|---|
test_profile_page_is_displayed | GET /profile returns HTTP 200 for an authenticated user. |
test_profile_information_can_be_updated | PATCH /profile updates name and email, clears email_verified_at. |
test_email_verification_status_is_unchanged_when_the_email_address_is_unchanged | PATCH /profile with the same email does not clear email_verified_at. |
test_user_can_delete_their_account | DELETE /profile with the correct password deletes the user and logs them out. |
test_correct_password_must_be_provided_to_delete_account | DELETE /profile with the wrong password returns a password error and does not delete the user. |
Continuous integration
The repository uses GitHub Actions with a single workflow defined in .github/workflows/deploy.yml. On every push to the main branch, the workflow SSH-deploys to the production Hetzner server — it does not currently run the PHPUnit suite in CI. The deploy script executes:
git pull origin main
composer install --optimize-autoloader --no-dev
npm install && npm run build
php artisan migrate --force
php artisan config:cache
php artisan route:cache
sudo systemctl restart php8.5-fpm
sudo supervisorctl restart xhealthxperience-worker:xhealthxperience-worker_00
If you want to add a CI test step before deployment, insert composer run test as a job step in deploy.yml before the SSH deploy action. This requires a test database to be available in the runner environment — the in-memory SQLite configuration in phpunit.xml makes this straightforward without any additional service containers.
Writing new tests
Follow these conventions when adding tests:
- Feature tests go in
tests/Feature/ (or a subdirectory). Extend Tests\TestCase and use RefreshDatabase.
- Unit tests go in
tests/Unit/. They extend PHPUnit\Framework\TestCase directly and should have no database or HTTP dependencies.
- The
app/ directory is the only code coverage source configured in phpunit.xml — keep non-app code out of coverage reports.
- Use
Notification::fake(), Mail::fake(), and Event::fake() to test side-effects without real infrastructure, exactly as the existing auth tests do.
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class MyNewTest extends TestCase
{
use RefreshDatabase;
public function test_something_works(): void
{
// Arrange, Act, Assert
$this->assertTrue(true);
}
}