grazulex / laravel-tddraft
A powerful Laravel package that provides LaravelTddraft functionality with modern PHP 8.3+ features.
Requires
- php: ^8.3
- illuminate/contracts: ^12.0
- illuminate/support: ^12.19
- nesbot/carbon: ^3.10
Requires (Dev)
- doctrine/dbal: ^4.2
- larastan/larastan: ^3.4
- laravel/pint: ^1.22
- orchestra/testbench: ^10.0
- pestphp/pest: ^3.8
- pestphp/pest-plugin-laravel: ^3.2
- rector/rector: ^2.0
Suggests
- pestphp/pest: Required to run and generate TDDraft tests (version >=3.0)
README

Set up Test-Driven Development environments in Laravel using Pest 3 with dedicated draft testing directories.
Overview
Laravel TDDraft helps you practice Test-Driven Development by providing a structured approach to draft testing in Laravel applications. It creates a separate testing environment for experimental tests that won't interfere with your main test suite or CI pipeline.
TDDraft โ CI Workflow

Visual representation of the TDDraft workflow and promotion to CI test suite
The package enables a clean separation between experimental draft tests and production-ready CI tests, allowing you to practice TDD without affecting your deployment pipeline.
โจ Features
- ๐ง Five-command TDD workflow: The core innovation that enables true Test-Driven Development without CI interference
- ๐ Creates dedicated
tests/TDDraft/
directory for draft tests - โ๏ธ Automatically configures PHPUnit and Pest to exclude drafts from main test runs
- ๐งช Native Pest 3 support with proper test isolation
- ๐ Automatic backup of configuration files before modification
- ๐ Unique reference tracking for test promotion from draft to CI
- ๐ NEW: Test status tracking - Automatic tracking of test execution results and history
- ๐ฏ Built for clean TDD workflow separation
- ๐ Easy graduation path from draft tests to production test suite
๐ง The Five-Command TDD Workflow
Laravel TDDraft is built around a five-command workflow that enables true Test-Driven Development. This structured approach is the key to the project - it provides a complete TDD cycle from experimentation to production.
๐ The Complete TDD Flow
The five commands work together in a specific sequence that mirrors the TDD Red-Green-Refactor cycle:
graph LR A[tdd:init] --> B[tdd:make] B --> C[tdd:test] C --> D{Test Passes?} D -->|No| E[Write Code] E --> C D -->|Yes| F[tdd:list] F --> G[tdd:promote] G --> H[CI Test Suite] style A fill:#ff9999 style B fill:#ffcc99 style C fill:#ffff99 style F fill:#ccffcc style G fill:#99ccffLoading
๐ Command Reference
Command | Role in TDD Flow | Description |
---|---|---|
tdd:init |
๐๏ธ Setup | Initialize TDDraft environment and configuration |
tdd:make |
๐งช Red Phase | Create a new failing test with unique tracking |
tdd:test |
๐ Red-Green Cycle | Run and iterate on draft tests until they pass |
tdd:list |
๐ Review | List and manage your draft tests before promotion |
tdd:promote |
๐ Graduate | Move ready tests to production CI test suite |
๐ฏ Why This Flow Matters
This five-command sequence is the core innovation of Laravel TDDraft. It solves the common TDD problems:
tdd:init
- Creates a separate space for experimental teststdd:make
- Enables rapid test creation without affecting CItdd:test
- Allows focused iteration on draft tests onlytdd:list
- Provides oversight of your TDD pipelinetdd:promote
- Ensures only ready tests reach production
๐ Complete Workflow Example
# 1. ๐๏ธ SETUP: Initialize your TDDraft environment (one-time) php artisan tdd:init # 2. ๐งช RED PHASE: Create failing tests for new features php artisan tdd:make "User can register" php artisan tdd:make "Password validation" --type=unit # 3. ๐ RED-GREEN CYCLE: Iterate until tests pass php artisan tdd:test --filter="User can register" # RED: Test fails # Write minimal code to make test pass... php artisan tdd:test --filter="User can register" # GREEN: Test passes # Refactor code... php artisan tdd:test --filter="User can register" # GREEN: Still passes # 4. ๐ REVIEW: Check all draft tests before promotion php artisan tdd:list --details # 5. ๐ GRADUATE: Move ready tests to CI suite php artisan tdd:promote tdd-20250718142530-Abc123
This workflow keeps your CI clean while enabling true TDD experimentation. Your main test suite never sees failing or experimental tests, but you can still practice proper Red-Green-Refactor cycles.
๐ Quick Start
1. Install the Package
composer require --dev grazulex/laravel-tddraft
2. Install Pest (Required)
๐ก Laravel TDDraft requires Pest v3.8 or higher:
composer require pestphp/pest --dev php artisan pest:install
3. Publish Configuration
php artisan vendor:publish --tag=tddraft-config
4. Initialize TDDraft
php artisan tdd:init
This command will:
- Create
tests/TDDraft/
directory structure - Configure PHPUnit to separate TDDraft tests from main suite
- Configure Pest to exclude TDDraft from default test runs
- Optionally create example test files
๐ Usage
Create Draft Tests
Create new TDDraft tests with unique tracking:
# Create a feature test php artisan tdd:make "User can register" # Create a unit test php artisan tdd:make "Password validation" --type=unit # Create test in a subdirectory php artisan tdd:make "API authentication" --path=Auth/Api # Create with custom class name php artisan tdd:make "Complex scenario" --class=MyCustomTest
Write Draft Tests
The generated test files include unique references and proper grouping:
<?php declare(strict_types=1); /** * TDDraft Test: User can register * * Reference: tdd-20250718142530-Abc123 * Type: feature * Created: 2025-07-18 14:25:30 */ it('user can register', function (): void { // TODO: Implement your test scenario here $response = $this->post('/register', [ 'name' => 'John Doe', 'email' => 'john@example.com', 'password' => 'password', 'password_confirmation' => 'password', ]); $response->assertStatus(201); $this->assertDatabaseHas('users', [ 'email' => 'john@example.com', ]); }) ->group('tddraft', 'feature', 'tdd-20250718142530-Abc123') ->todo('Implement the test scenario for: user can register');
Run Tests Separately
# Run only main tests (excludes TDDraft) pest # Run only TDDraft tests (with automatic status tracking!) php artisan tdd:test # Run TDDraft tests with options php artisan tdd:test --filter="user registration" php artisan tdd:test --coverage php artisan tdd:test --parallel php artisan tdd:test --stop-on-failure # Filter by type pest --testsuite=tddraft --group=feature pest --testsuite=tddraft --group=unit # Filter by specific reference pest --testsuite=tddraft --group=tdd-20250718142530-Abc123 # Alternative: use pest directly pest --testsuite=tddraft # Run all tests including TDDraft pest --testsuite=default,tddraft
Test Status Tracking (NEW)
Laravel TDDraft now automatically tracks your test execution results:
# Run tests with automatic status tracking php artisan tdd:test # Status is automatically saved to tests/TDDraft/.status.json # Each test result is linked to its unique reference for precise tracking
Status tracking provides:
- Automatic recording of test results (passed/failed/error/skipped)
- Historical tracking of status changes over time
- Reference-based linking for audit trails
- JSON storage for easy integration with other tools
List and Manage Tests
Use the tdd:list
command to view and manage your draft tests:
# List all draft tests php artisan tdd:list # Show detailed information php artisan tdd:list --details # Filter by test type php artisan tdd:list --type=feature php artisan tdd:list --type=unit # Filter by directory path php artisan tdd:list --path=Auth
Example output:
๐ TDDraft Tests List
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโฌโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ Reference โ Name โ Type โ Status โ File โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโผโโโโโโโโโโผโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโโโโโโโโโโโค
โ tdd-20250718142530-Abc123โ User can register โ feature โ โ
Passed โ UserCanRegisterTest.php โ
โ tdd-20250718141045-Def456โ Password validation โ unit โ โ Failed โ PasswordValidationTest.phpโ
โ tdd-20250718140012-Ghi789โ API authentication โ feature โ โ Unknown โ Auth/ApiAuthTest.php โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโดโโโโโโโโโโดโโโโโโโโโโโโโโดโโโโโโโโโโโโโโโโโโโโโโโโโโ
๐ Total: 3 draft test(s)
๐ก Tips:
โข Run specific test: php artisan tdd:test --filter="<reference>"
โข Run by type: php artisan tdd:test --filter="feature"
โข Promote draft: php artisan tdd:promote <reference>
Graduate Tests
When your draft test is ready for production, you have two options for promoting it to your main test suite:
Option 1: Automated Promotion (Recommended)
Use the tdd:promote
command with the unique reference for automated promotion:
# Basic promotion (promotes to Feature directory by default) php artisan tdd:promote tdd-20250718142530-Abc123 # Promote to specific directory php artisan tdd:promote tdd-20250718142530-Abc123 --target=Unit # Promote with custom file name php artisan tdd:promote tdd-20250718142530-Abc123 --new-file=UserRegistrationTest # Append to existing test file php artisan tdd:promote tdd-20250718142530-Abc123 --file=ExistingTest.php # Keep the original draft file php artisan tdd:promote tdd-20250718142530-Abc123 --keep-draft # Force overwrite without confirmation php artisan tdd:promote tdd-20250718142530-Abc123 --force
Option 2: Manual Promotion
For manual control, you can still promote tests manually:
# Step 1: Note the unique reference from your test file # Example test header: # /** # * TDDraft Test: User can register # * Reference: tdd-20250718142530-Abc123 # * Type: feature # * Created: 2025-07-18 14:25:30 # */ # Step 2: Move the test file to your main test suite mv tests/TDDraft/UserCanRegisterTest.php tests/Feature/Auth/UserRegistrationTest.php # Step 3: Update the test groups (remove 'tddraft', keep reference for tracking) # Change: ->group('tddraft', 'feature', 'tdd-20250718142530-Abc123') # To: ->group('feature', 'tdd-20250718142530-Abc123') # Step 4: Run the promoted test to ensure it works in main suite pest tests/Feature/Auth/UserRegistrationTest.php # Step 5: Run full test suite to verify no conflicts pest
Tracking Test Lineage
The unique reference system allows you to:
- Track which tests originated from TDDraft
- Monitor test evolution from draft to production
- Maintain audit trail for compliance
- Link CI failures back to original draft intent
๐ Configuration
The package configuration is published to config/tddraft.php
:
return [ /** * Test status tracking configuration * * NEW: Controls how test execution results are tracked and persisted. */ 'status_tracking' => [ // Enable or disable status tracking 'enabled' => env('LARAVEL_TDDRAFT_STATUS_TRACKING_ENABLED', true), // File path where test statuses are saved (relative to Laravel base path) 'file_path' => env('LARAVEL_TDDRAFT_STATUS_FILE', 'tests/TDDraft/.status.json'), // Keep history of status changes for each test 'track_history' => env('LARAVEL_TDDRAFT_TRACK_HISTORY', true), // Maximum number of history entries to keep per test 'max_history_entries' => env('LARAVEL_TDDRAFT_MAX_HISTORY', 50), ], ];
Environment Variables:
# Enable/disable status tracking LARAVEL_TDDRAFT_STATUS_TRACKING_ENABLED=true # Configure status file location LARAVEL_TDDRAFT_STATUS_FILE=tests/TDDraft/.status.json # Control history tracking LARAVEL_TDDRAFT_TRACK_HISTORY=true LARAVEL_TDDRAFT_MAX_HISTORY=50
๐งช Example Draft Test
<?php declare(strict_types=1); it('should fail initially - this is normal for TDDraft', function (): void { // This test intentionally fails to demonstrate the TDD "red" phase expect(false)->toBeTrue('This draft needs implementation!'); })->group('tddraft', 'feature', 'example-red-phase'); it('can be promoted when ready', function (): void { // When this passes, you can promote it to your main test suite expect(true)->toBeTrue(); })->group('tddraft', 'feature', 'example-green-phase');
๐ Documentation
For comprehensive documentation, see the docs/
directory:
๐ง Requirements
- PHP 8.3+
- Laravel 12.19+
- Pest 3.8+
๐ค Contributing
Please see CONTRIBUTING.md for details on how to contribute to this project.
๐ License
This package is open-source software licensed under the MIT license.
Made with โค๏ธ for the Laravel and Pest community