Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

React Phpunit Run Tests In Fiber Laravel Package

wyrihaximus/react-phpunit-run-tests-in-fiber

PHPUnit trait to run each test inside a PHP Fiber, making it easy to use ReactPHP async/await in tests. Includes optional per-test or per-class timeout attributes to fail slow tests (without stopping the running fiber).

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Installation: Add the package to your Laravel project’s devDependencies:

    composer require --dev wyrihaximus/react-phpunit-run-tests-in-fiber
    

    Ensure your project meets the requirements: PHP 8.4+, PHPUnit 12+, and react/async (automatically included as a dependency).

  2. First Use Case:

    • Use this package only for testing ReactPHP-based async logic (e.g., fibers, promises, event loops).
    • Add the trait to a test class:
      use PHPUnit\Framework\TestCase;
      use WyriHaximus\React\PHPUnit\RunTestsInFibersTrait;
      
      final class AsyncServiceTest extends TestCase
      {
          use RunTestsInFibersTrait;
      
          #[test]
          public function itAwaitsPromisesCorrectly(): void
          {
              $result = \React\Async\await(new \React\Promise\FulfilledPromise(true));
              self::assertTrue($result);
          }
      }
      
    • Run tests with php artisan test (or your preferred PHPUnit command).

Implementation Patterns

1. Trait Integration

  • Apply the trait only to test classes requiring fiber execution (e.g., async HTTP clients, WebSocket handlers).
  • Avoid mixing sync and async tests in the same class to prevent unexpected behavior.

2. Async Workflow Testing

  • Use await() for promises in fiber-aware tests:
    public function itHandlesAsyncOperations(): void
    {
        $promise = new \React\Promise\Promise(function ($resolve) {
            $resolve('success');
        });
        self::assertEquals('success', \React\Async\await($promise));
    }
    
  • Test event loops or async services by injecting a React\EventLoop\LoopInterface and running tests in fibers.

3. Timeout Management

  • Set class-level defaults for test timeouts (e.g., 10 seconds):
    #[\WyriHaximus\React\PHPUnit\TimeOut(10)]
    final class AsyncServiceTest extends TestCase
    {
        use RunTestsInFibersTrait;
    }
    
  • Override per-test with method-level annotations:
    #[\WyriHaximus\React\PHPUnit\TimeOut(2)]
    public function itTimesOutQuickly(): void { ... }
    

4. Laravel-Specific Patterns

  • Async HTTP Clients: Test GuzzleHttp\Promise\PromiseInterface or React\Http\Message\Response in fibers:
    public function itFetchesDataAsync(): void
    {
        $client = new \React\Http\Client();
        $response = \React\Async\await($client->send(\React\Http\Message\Request::create('https://api.example.com')));
        self::assertEquals(200, $response->getStatusCode());
    }
    
  • Queue Workers: Mock async queue jobs and test fiber execution:
    public function itProcessesJobsInFiber(): void
    {
        $job = new AsyncJob();
        $result = \React\Async\await($job->handle());
        self::assertTrue($result);
    }
    

5. Database Transactions

  • Avoid mixing fiber tests with Laravel’s database transactions (e.g., DatabaseTransactions trait). Fibers may interfere with transaction rollbacks.
  • Use in-memory databases (e.g., SQLite) or disable transactions for async tests:
    protected function setUp(): void
    {
        parent::setUp();
        $this->withoutExceptionHandling();
        $this->withoutTransactions(); // Critical for fiber tests
    }
    

Gotchas and Tips

Pitfalls

  1. Fiber Context Leaks:

    • Fibers cannot be killed mid-execution. Long-running or stuck fibers will block the test suite.
    • Fix: Always set reasonable timeouts (e.g., [TimeOut(5)]) and avoid infinite loops in tests.
  2. Conflicts with Laravel’s Sync Tools:

    • Queue Workers: Laravel’s queue system (e.g., queue:work) uses a separate process and won’t interact with fibers.
    • HTTP Tests: Http::fake() or Http::assertSent() may not work as expected in fiber tests.
    • Fix: Isolate fiber tests in dedicated test classes or namespaces.
  3. Database Transactions:

    • Fibers may not play nicely with Laravel’s transaction rollbacks, leading to "connection closed" errors.
    • Fix: Use withoutTransactions() or avoid transactions in fiber tests.
  4. Promise Rejections:

    • Unhandled promise rejections in fibers will crash the test silently.
    • Fix: Wrap await() calls in try-catch blocks:
      try {
          $result = \React\Async\await($promise);
      } catch (\React\Promise\RejectedPromiseException $e) {
          self::fail($e->getMessage());
      }
      

Debugging Tips

  1. Check Fiber Status:

    • Verify tests run in a fiber by logging the current fiber:
      public function itRunsInFiber(): void
      {
          self::assertNotNull(\React\Async\getCurrentFiber());
      }
      
  2. Timeout Debugging:

    • If a test hangs, check the timeout value. Add debug logs:
      #[\WyriHaximus\React\PHPUnit\TimeOut(1)]
      public function itTimesOut(): void
      {
          error_log('Test started at: ' . time());
          \React\Async\await(new \React\Promise\Deferred());
      }
      
  3. Event Loop Conflicts:

    • If tests fail with "Loop already running," ensure no other ReactPHP components (e.g., HTTP clients) are active.
    • Fix: Reset the loop in setUp():
      protected function setUp(): void
      {
          parent::setUp();
          \React\EventLoop\Factory::create()->run();
      }
      

Extension Points

  1. Custom Timeouts:

    • Extend the TimeOut attribute to support dynamic timeouts (e.g., based on environment variables):
      #[\WyriHaximus\React\PHPUnit\TimeOut(env('TEST_TIMEOUT', 10))]
      
  2. Fiber-Specific Assertions:

    • Add helper methods to assert fiber behavior:
      protected function assertFiberIsRunning(): void
      {
          self::assertNotNull(\React\Async\getCurrentFiber());
      }
      
  3. Integration with Laravel Packages:

    • For packages like spatie/laravel-react, use this trait to test async features:
      use Spatie\React\React;
      
      public function itProcessesReactEvents(): void
      {
          $result = \React\Async\await(React::process());
          self::assertTrue($result);
      }
      

Performance Considerations

  • Fibers add overhead. Use them only for async logic; keep sync tests separate.
  • Avoid nesting fibers (e.g., await inside another await) unless necessary.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
codraw/framework-extra-bundle
codraw/messenger
codraw/security
codraw/mailer
codraw/contracts
codraw/profiling
codraw/dependency-injection
codraw/tester
codraw/core
nexmo/api-specification
capell-app/block-library
axium/identity
cetria/laravel-dummy-models
cetria/reflection-helper
agropredict/sso-auth-bundle
evolvestudio/spam-protection
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony