Agent skill
pest-testing
Comprehensive guidance for writing Pest v4 tests in Laravel applications, including feature tests, unit tests, and browser tests. Use this skill when writing tests, implementing test-driven development, testing APIs, creating browser automation tests, or ensuring code quality through testing.
Install this agent skill to your Project
npx add-skill https://github.com/majiayu000/claude-skill-registry/tree/main/skills/development/pest-testing
SKILL.md
Pest Testing Skill
This skill provides expert guidance for writing high-quality tests with Pest v4 in Laravel applications, covering feature tests, unit tests, browser tests, and testing best practices.
Purpose
Provide comprehensive Pest v4 testing guidance covering:
- Core Pest syntax and expectations API
- Feature and unit testing in Laravel
- Browser testing with Pest v4 (new feature)
- HTTP testing, authentication, and authorization
- Database testing and factories
- Mocking and faking Laravel services
- Testing best practices and patterns
- Datasets for efficient test organization
When to Use
Use this skill when:
- Writing or updating tests
- Implementing test-driven development (TDD)
- Testing APIs and HTTP endpoints
- Testing authentication and authorization
- Creating browser automation tests
- Testing with model factories
- Using datasets to avoid duplicate tests
- Mocking services or external dependencies
- Verifying features work correctly
- Ensuring code quality and preventing regressions
Core Principles
1. Most Tests Should Be Feature Tests
Focus on feature tests that verify complete workflows:
// ✅ GOOD - Feature test testing full workflow
it('creates a post', function () {
$user = User::factory()->create();
$response = $this->actingAs($user)->post('/posts', [
'title' => 'My Post',
'body' => 'Content',
]);
$response->assertCreated();
$this->assertDatabaseHas('posts', [
'title' => 'My Post',
'user_id' => $user->id,
]);
});
// Unit tests are for isolated logic
it('calculates total correctly', function () {
$calculator = new Calculator();
expect($calculator->add(2, 2))->toBe(4);
});
2. Always Use Model Factories
Never manually create models - use factories:
// ✅ CORRECT - Use factories
$user = User::factory()->create();
$posts = Post::factory()->count(3)->create();
// Check for factory states
$admin = User::factory()->admin()->create();
$publishedPost = Post::factory()->published()->create();
// ❌ WRONG - Manual creation
$user = User::create([
'name' => 'Test',
'email' => 'test@example.com',
// ... many fields
]);
3. Use Datasets to Avoid Duplication
When testing similar scenarios with different data, use datasets:
// ✅ GOOD - Using dataset
it('validates email format', function (string $email, bool $valid) {
$validator = validator(['email' => $email], ['email' => 'email']);
expect($validator->passes())->toBe($valid);
})->with([
['valid@example.com', true],
['invalid', false],
['test@test.co', true],
['@example.com', false],
]);
// ❌ WRONG - Duplicate tests
it('accepts valid email', function () {
$validator = validator(['email' => 'valid@example.com'], ['email' => 'email']);
expect($validator->passes())->toBeTrue();
});
it('rejects invalid email', function () {
$validator = validator(['email' => 'invalid'], ['email' => 'email']);
expect($validator->passes())->toBeFalse();
});
4. Use Specific Assertions
Prefer specific assertions over generic ones:
// ✅ GOOD - Specific assertions
$response->assertOk(); // 200
$response->assertCreated(); // 201
$response->assertNoContent(); // 204
$response->assertNotFound(); // 404
$response->assertForbidden(); // 403
$response->assertUnprocessable();// 422
// ❌ AVOID - Generic assertions
$response->assertStatus(200);
$response->assertStatus(404);
5. Import Mock Function When Needed
Always import the mock function before using it:
use function Pest\Laravel\mock;
it('mocks a service', function () {
$mock = mock(PaymentService::class);
$mock->shouldReceive('charge')
->once()
->andReturn(true);
// Test code
});
Read references/core.md for complete Pest syntax and expectations API.
Running Tests
Run All Tests
php artisan test
Run Specific File
php artisan test tests/Feature/PostTest.php
Run with Filter
php artisan test --filter=login
php artisan test --filter="can create posts"
Run Specific Group
php artisan test --group=integration
Best Practice: Run the minimal number of tests using an appropriate filter when developing, then run the full suite before committing.
Feature Testing Patterns
Basic HTTP Testing
it('displays homepage', function () {
$response = $this->get('/');
$response->assertOk()
->assertSee('Welcome');
});
it('creates resource', function () {
$user = User::factory()->create();
$response = $this->actingAs($user)->post('/posts', [
'title' => 'My Post',
'body' => 'Content',
]);
$response->assertCreated()
->assertJson(['title' => 'My Post']);
});
Authentication Testing
it('requires authentication', function () {
$response = $this->get('/dashboard');
$response->assertRedirect('/login');
});
it('allows authenticated users', function () {
$user = User::factory()->create();
$response = $this->actingAs($user)->get('/dashboard');
$response->assertOk();
});
Validation Testing
it('validates required fields', function () {
$user = User::factory()->create();
$response = $this->actingAs($user)->post('/posts', []);
$response->assertUnprocessable()
->assertJsonValidationErrors(['title', 'body']);
});
Read references/laravel.md for comprehensive Laravel testing patterns.
Pest v4 Browser Testing
Pest v4 introduces powerful browser testing capabilities:
use function Pest\Laravel\visit;
it('can login', function () {
$user = User::factory()->create([
'password' => bcrypt('password'),
]);
$page = visit('/login');
$page->fill('email', $user->email)
->fill('password', 'password')
->click('Login')
->assertPath('/dashboard')
->assertSee("Welcome, {$user->name}");
});
Browser Testing Features
- Real browser testing - Chrome, Firefox, Safari
- JavaScript support - Full JS execution
- Multiple devices - Test on different viewports/devices
- Dark mode testing - Test light and dark color schemes
- Screenshots - Capture on failure or manually
- Touch gestures - Test mobile interactions
- Wait utilities - Wait for dynamic content
Browser Test Best Practices
it('has no JavaScript errors', function () {
$pages = visit(['/', '/about', '/contact']);
$pages->assertNoJavascriptErrors()
->assertNoConsoleLogs();
});
it('works in dark mode', function () {
$page = visit('/', colorScheme: 'dark');
$page->assertSee('Welcome')
->assertNoJavascriptErrors();
});
it('works on mobile', function () {
$page = visit('/', device: 'iPhone 14 Pro');
$page->assertSee('Welcome')
->assertVisible('.mobile-menu');
});
Read references/browser.md for comprehensive browser testing guide.
Using Model Factories
Basic Factory Usage
// Single model
$user = User::factory()->create();
// Multiple models
$users = User::factory()->count(5)->create();
// With specific attributes
$user = User::factory()->create([
'name' => 'John Doe',
'email' => 'john@example.com',
]);
// With relationships
$user = User::factory()
->has(Post::factory()->count(3))
->create();
Using Factory States
Check if factories have custom states before manually setting attributes:
// Check factory for states like:
$admin = User::factory()->admin()->create();
$publishedPost = Post::factory()->published()->create();
$verifiedUser = User::factory()->verified()->create();
Testing with RefreshDatabase
Clean database state between tests:
use Illuminate\Foundation\Testing\RefreshDatabase;
uses(RefreshDatabase::class);
it('creates user', function () {
$user = User::factory()->create();
expect(User::count())->toBe(1);
});
Mocking and Faking
Faking Laravel Services
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Queue;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Notification;
use Illuminate\Support\Facades\Storage;
it('sends email', function () {
Mail::fake();
// Trigger email
Mail::assertSent(WelcomeEmail::class);
});
it('dispatches job', function () {
Queue::fake();
// Trigger job
Queue::assertPushed(ProcessPodcast::class);
});
it('dispatches event', function () {
Event::fake();
// Trigger event
Event::assertDispatched(UserCreated::class);
});
Mocking Classes
use function Pest\Laravel\mock;
it('mocks external service', function () {
$mock = mock(PaymentGateway::class);
$mock->shouldReceive('charge')
->once()
->with(100)
->andReturn(['status' => 'success']);
// Test code that uses PaymentGateway
});
Test Organization
Grouping Related Tests
describe('User Management', function () {
it('creates users', function () {
//
});
it('updates users', function () {
//
});
it('deletes users', function () {
//
});
});
Using Tags/Groups
it('is an integration test', function () {
//
})->group('integration');
it('is slow', function () {
//
})->group('slow', 'integration');
// Run: php artisan test --group=integration
Reference Files
This skill includes detailed reference files:
references/core.md- Pest syntax, expectations API, assertions, datasets, mocking, lifecycle hooksreferences/browser.md- Browser testing, interactions, waiting, device testing, screenshots, smoke testingreferences/laravel.md- HTTP testing, authentication, validation, database testing, faking services
Read the appropriate reference file(s) when working on specific testing tasks.
Testing Workflow
Test-Driven Development (TDD)
- Write failing test - Define expected behavior
- Write minimal code - Make test pass
- Refactor - Improve code while keeping tests green
- Repeat - For next feature or behavior
Testing Existing Features
- Write test for happy path - Normal, successful flow
- Write test for failure paths - Error cases, validation failures
- Write test for edge cases - Empty data, null values, boundaries
- Run tests - Verify all pass
- Refactor if needed - Improve while keeping tests green
Best Practices Summary
- ✅ Write feature tests - Most tests should test complete workflows
- ✅ Use factories - Always use model factories for test data
- ✅ Use datasets - Avoid duplicate tests with different data
- ✅ Use specific assertions -
assertOk()notassertStatus(200) - ✅ Import mock function -
use function Pest\Laravel\mock; - ✅ Use RefreshDatabase - Clean database between tests
- ✅ Check factory states - Use existing states before manual setup
- ✅ Test all paths - Happy, failure, and edge cases
- ✅ Run minimal tests - Use filters when developing
- ✅ Run full suite - Before committing changes
- ✅ Use browser tests - For JavaScript-heavy features
- ✅ Check for JS errors - Use
assertNoJavascriptErrors() - ✅ Test both themes - Verify light and dark modes
- ✅ Keep tests isolated - Each test should be independent
- ✅ Use descriptive names - Tests should read like specifications
Common Testing Tasks
Testing a New Feature
- Create test file:
php artisan make:test FeatureTest --pest - Write test for expected behavior
- Run test:
php artisan test --filter=FeatureName - Implement feature
- Verify test passes
- Add tests for edge cases
- Run full suite:
php artisan test
Testing API Endpoints
- Test successful requests (2xx status)
- Test validation errors (422 status)
- Test authentication (401/403 status)
- Test not found (404 status)
- Verify JSON structure and data
- Test with different user permissions
Testing Browser Interactions
- Create browser test in
tests/Browser/ - Visit the page
- Interact with elements (click, type, select)
- Assert expected results
- Check for JavaScript errors
- Test on different devices/viewports
- Test both color schemes
This skill ensures tests are comprehensive, maintainable, and follow Pest v4 best practices for Laravel applications.
Recommended Agent Skills
Expand your agent's capabilities with these related and highly-rated skills.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
agent-ops-spec
Manage specification documents in .agent/specs/. Use when user provides requirements, acceptance criteria, or feature descriptions that need to be tracked and validated against implementation.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-testing
Test strategy, execution, and coverage analysis. Use when designing tests, running test suites, or analyzing test results beyond baseline checks.
agent-ops-state
Maintain .agent state files. Use at session start, after meaningful steps, and before concluding: read/update constitution/memory/focus/issues/baseline consistently.
Didn't find tool you were looking for?