Testing Overview
Auto Commerce uses a comprehensive testing strategy covering backend, frontend, and end-to-end testing.
Testing Layers
| Layer | Framework | Purpose |
|---|---|---|
| Backend | Pest PHP | API, services, models |
| Frontend | Jest/Vitest | React components, hooks |
| E2E | Playwright | Full user workflows |
Quick Links
- E2E Testing - End-to-end tests with Playwright
- Module Testing - Module-specific tests
- Backend testing - Covered below
Backend Testing
Auto Commerce uses Pest PHP for backend testing, providing an elegant and expressive testing experience. The testing framework covers unit tests, feature tests, and module-specific tests.
Testing Stack
- Pest PHP - Modern PHP testing framework
- PHPUnit - Underlying test runner
- Laravel Testing Utilities - HTTP testing, database assertions
- Database Transactions - Automatic rollback after each test
Running Tests
All Tests
# Run all tests
cd backend
./vendor/bin/pest
# With coverage
./vendor/bin/pest --coverage
Specific Test Files
# Run a specific test file
./vendor/bin/pest tests/Feature/Auth/LoginTest.php
# Run tests matching a pattern
./vendor/bin/pest --filter="can login"
Test Suites
# Run unit tests only
./vendor/bin/pest tests/Unit
# Run feature tests only
./vendor/bin/pest tests/Feature
Test Categories
Unit Tests (tests/Unit/)
Test individual classes and methods in isolation:
- Models - Eloquent model tests (scopes, accessors, relationships)
- Services - Business logic service tests
- Providers - Service provider tests
Feature Tests (tests/Feature/)
Test complete features through HTTP requests:
- Auth - Authentication flows (login, logout, registration)
- API - API endpoint tests
- Modules - Module system tests
Module Tests (modules/*/backend/tests/)
Each module can have its own test suite:
- Feature - Module API endpoint tests
- Unit - Module-specific unit tests
Test Directory Structure
backend/
├── tests/
│ ├── Feature/
│ │ ├── Auth/
│ │ │ ├── LoginTest.php
│ │ │ ├── LogoutTest.php
│ │ │ └── RegistrationTest.php
│ │ ├── Modules/
│ │ │ └── ModuleApiTest.php
│ │ └── Security/
│ │ └── TwoFactorAuthTest.php
│ ├── Unit/
│ │ ├── Models/
│ │ │ ├── ModuleTest.php
│ │ │ └── ModuleInstallationTest.php
│ │ ├── Services/
│ │ │ └── ModuleManagerTest.php
│ │ └── Providers/
│ │ └── ModulesServiceProviderTest.php
│ ├── Pest.php # Global test configuration
│ ├── TestCase.php # Base test case
│ └── ModuleTestCase.php # Module testing base class
Writing Tests
Basic Test Structure
<?php
use App\Models\User;
use Illuminate\Foundation\Testing\DatabaseTransactions;
uses(Tests\TestCase::class, DatabaseTransactions::class);
describe('User Registration', function () {
it('can register a new user', function () {
$response = $this->postJson('/api/v1/auth/register', [
'name' => 'Test User',
'email' => 'test@example.com',
'password' => 'password123',
'password_confirmation' => 'password123',
]);
$response->assertStatus(201);
expect(User::where('email', 'test@example.com')->exists())->toBeTrue();
});
});
Testing with Authentication
use App\Models\User;
use Laravel\Passport\Passport;
it('can access protected route when authenticated', function () {
$user = User::factory()->create();
Passport::actingAs($user);
$response = $this->getJson('/api/v1/profile');
$response->assertStatus(200);
});
Testing with Tenant Context
use App\Models\Tenant;
it('can access tenant-specific data', function () {
$tenant = Tenant::create(['id' => 'test-tenant', 'name' => 'Test Tenant']);
// Initialize tenant context
tenancy()->initialize($tenant);
// Run your test...
// End tenant context
tenancy()->end();
// Cleanup
$tenant->delete();
});
Configuration
phpunit.xml
The phpunit.xml file configures test suites:
<testsuites>
<testsuite name="Unit">
<directory>tests/Unit</directory>
</testsuite>
<testsuite name="Feature">
<directory>tests/Feature</directory>
</testsuite>
<testsuite name="Modules">
<directory>../modules/*/backend/tests</directory>
</testsuite>
</testsuites>
Pest.php
Global test configuration in tests/Pest.php:
<?php
uses(Tests\TestCase::class, DatabaseTransactions::class)->in('Feature', 'Unit');
// Custom expectations
expect()->extend('toBeActiveModule', function () {
return $this->toBeInstanceOf(Module::class)
->and($this->value->is_active)->toBeTrue();
});
Best Practices
- Use DatabaseTransactions - Automatically rollback database changes after each test
- Test in isolation - Each test should be independent and not rely on other tests
- Use factories - Leverage Laravel factories for creating test data
- Test edge cases - Include tests for error conditions and boundary cases
- Keep tests focused - Each test should verify one specific behavior
- Use meaningful names - Test names should describe what is being tested
Related Documentation
- E2E Testing - End-to-end tests with Playwright
- Module Testing - Testing modules
- API Testing - Testing API endpoints
- Database Testing - Database test strategies