Skip to content

Conversation

@binaryfire
Copy link
Contributor

Summary

This PR ports Laravel Orchestral Testbench's testing infrastructure to Hypervel, bringing familiar testing patterns and PHP 8 attribute-based test configuration to Hypervel.

Key Features Ported from Laravel Testbench

  • defineEnvironment() hook - Pre-boot application configuration, matching Laravel's defineEnvironment() pattern
  • Package provider/alias registration - getPackageProviders() and getPackageAliases() methods for package testing
  • Route definition helpers - defineRoutes() and defineWebRoutes() with automatic web middleware group wrapping
  • Database migration hooks - defineDatabaseMigrations(), destroyDatabaseMigrations(), defineDatabaseSeeders()
  • PHP 8 Testing Attributes - Full attribute-based test configuration system

Testing Attributes (Following Laravel Testbench Patterns)

Attribute Description
#[WithConfig('key', 'value')] Set config values directly
#[DefineEnvironment('methodName')] Call a method with $app for environment setup
#[DefineRoute('methodName')] Call a method with $router for route definition
#[DefineDatabase('methodName')] Call a method for database setup (supports deferred execution)
#[WithMigration('path')] Load migration paths
#[RequiresEnv('VAR')] Skip test if environment variable is missing
#[ResetRefreshDatabaseState] Reset database state between test classes
#[Define('group', 'method')] Meta-attribute shorthand (resolves to DefineEnvironment/DefineDatabase/DefineRoute)

Lifecycle Hooks (Matching Laravel Testbench)

  • BeforeAll / AfterAll - Class-level lifecycle (static, runs once per test class)
  • BeforeEach / AfterEach - Test-level lifecycle (runs for each test method)
  • Invokable - Direct invocation with app instance
  • Actionable - Method delegation with closure callback

Hypervel-Specific Adaptations

While following Laravel Testbench patterns closely, this implementation includes Hypervel-specific adaptations:

  • Coroutine context awareness - BeforeEach/AfterEach attributes execute inside runInCoroutine(), matching where setUpTraits() runs in Foundation TestCase
  • Hypervel Router API - Route group middleware uses Hypervel's $router->group() signature
  • Automatic route registration - setUpApplicationRoutes() is called automatically in afterApplicationCreated, so routes defined via defineRoutes() are available without manual setup
  • Smart web routes handling - Uses reflection to skip empty web routes group registration, preventing interference with Hypervel's RouteFileCollector when defineWebRoutes() isn't overridden
  • No route caching - Skipped as Hypervel/Hyperf doesn't have Laravel-style route caching
  • No annotation/pest support - Simplified TestingFeature orchestrator without legacy patterns

Example Usage

#[WithConfig('app.name', 'Test App')]
#[ResetRefreshDatabaseState]
class MyPackageTest extends \Hypervel\Testbench\TestCase
{
    protected function getPackageProviders($app): array
    {
        return [MyServiceProvider::class];
    }

    protected function defineRoutes($router): void
    {
        $router->get('/api/test', fn() => 'ok');
    }

    protected function defineWebRoutes($router): void
    {
        $router->get('/test', fn() => 'ok'); // Has 'web' middleware
    }

    #[DefineEnvironment('setupCustomEnv')]
    #[Define('env', 'setupAnotherEnv')]  // Meta-attribute shorthand
    public function testSomething(): void
    {
        $this->assertEquals('Test App', config('app.name'));
    }

    protected function setupCustomEnv($app): void
    {
        $app->get('config')->set('custom.key', 'value');
    }
}

Files Changed

New Files (28)

Foundation Contracts (src/foundation/src/Testing/Contracts/Attributes/):

  • TestingFeature.php, Resolvable.php, Actionable.php, Invokable.php
  • BeforeEach.php, AfterEach.php, BeforeAll.php, AfterAll.php

Foundation Attributes (src/foundation/src/Testing/Attributes/):

  • DefineEnvironment.php, WithConfig.php, DefineRoute.php, DefineDatabase.php
  • WithMigration.php, RequiresEnv.php, ResetRefreshDatabaseState.php, Define.php

Foundation Infrastructure (src/foundation/src/Testing/):

  • AttributeParser.php - Parses class/method attributes with Resolvable support
  • Concerns/HandlesAttributes.php - Attribute parsing trait
  • Concerns/InteractsWithTestCase.php - Caching and lifecycle execution
  • Features/TestingFeature.php - Orchestrator for default + attribute flows
  • Features/FeaturesCollection.php - Collection for deferred callbacks

Testbench Traits (src/testbench/src/Concerns/):

  • CreatesApplication.php - Package providers/aliases
  • HandlesRoutes.php - Route definition helpers
  • HandlesDatabases.php - Database migration helpers

Tests (7 test files with comprehensive coverage)

Modified Files (3)

  • src/foundation/src/Testing/Concerns/InteractsWithContainer.php - Added defineEnvironment() hook
  • src/testbench/src/TestCase.php - Integrated new traits with coroutine-aware lifecycle
  • tests/Sanctum/AuthenticateRequestsTest.php - Refactored to use new testbench pattern (getPackageProviders, defineEnvironment, defineRoutes)

Phase 1: defineEnvironment hook
- Add defineEnvironment($app) call in refreshApplication() before app boot
- Add empty defineEnvironment() method for subclass override
- Add DefineEnvironmentTest

Phase 2: Attribute contracts
- TestingFeature: marker interface
- Resolvable: resolve() for meta-attributes (does NOT extend TestingFeature)
- Actionable: handle($app, Closure $action)
- Invokable: __invoke($app)
- BeforeEach/AfterEach: per-test lifecycle hooks
- BeforeAll/AfterAll: per-class lifecycle hooks

Phase 3: AttributeParser and FeaturesCollection
- AttributeParser: parses class/method attributes with inheritance and Resolvable support
- FeaturesCollection: collection for deferred attribute callbacks

Phase 4.2: HandlesAttributes trait
- parseTestMethodAttributes() for executing attribute callbacks
- Static caching for class/method attributes
- usesTestingConcern() to check trait usage
- usesTestingFeature() for programmatic attribute registration
- resolvePhpUnitAttributes() merges all attribute sources
- Lifecycle methods: setUpTheTestEnvironmentUsingTestCase,
  tearDownTheTestEnvironmentUsingTestCase,
  setUpBeforeClassUsingTestCase, tearDownAfterClassUsingTestCase
Simplified orchestrator for default + attribute flows.
Uses inline flag-based memoization instead of Orchestra's once() helper.
No annotation/pest support - not needed for Hypervel.
- DefineEnvironment: calls test method with $app
- WithConfig: sets config value directly
- DefineRoute: calls test method with $router
- DefineDatabase: deferred execution, resets RefreshDatabaseState
- ResetRefreshDatabaseState: resets database state before/after all tests
- WithMigration: loads explicit migration paths
- RequiresEnv: skips test if env var missing
- Define: meta-attribute resolving to env/db/route attributes
…rastructure

- Change Actionable::handle() implementations to return mixed instead of void
- Change Invokable::__invoke() implementations to return mixed instead of void
- Fix TestingFeature orchestrator closure return type
- Add @phpstan-ignore for rescue callback type resolution
- Update setUpTheTestEnvironmentUsingTestCase() to execute all attribute types (Invokable, Actionable, BeforeEach)
- Call setUpApplicationRoutes() automatically in afterApplicationCreated
- Add reflection check to skip empty web routes group registration
- Refactor Sanctum tests to use new testbench pattern (getPackageProviders,
  defineEnvironment, defineRoutes)
- Add tests for route accessibility and routing without defineWebRoutes
…ritance

- Mark parseTestMethodAttributes() as @internal to prevent misuse
- Add test verifying Define meta-attribute is resolved by AttributeParser
- Add test verifying Define meta-attribute is executed through lifecycle
- Add tests verifying attributes are inherited from parent TestCase classes
Add proper type hints following existing codebase conventions:
- Use `ApplicationContract` alias for contract type hints
- Use `Router` type hints for route definition methods
- Update all contracts, attributes, traits, and test files

This improves type safety while maintaining consistency with the
existing codebase pattern where 20+ files use the ApplicationContract
alias convention.
@albertcht albertcht requested a review from Copilot January 24, 2026 06:27
@albertcht albertcht added the feature New feature or request label Jan 24, 2026
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Ports Laravel Testbench-style package testing infrastructure into Hypervel, including hooks for environment/routes/database setup and PHP 8 attribute-based test configuration.

Changes:

  • Added a new attribute-based testing feature system (parser, lifecycle execution, attribute contracts, and built-in attributes like WithConfig, DefineEnvironment, etc.).
  • Added Testbench traits for package provider/alias registration, route helpers (including optional web-group wrapping), and database hooks; integrated them into Hypervel\Testbench\TestCase.
  • Added/updated tests to validate the new Testbench patterns and attribute/lifecycle behavior (including refactoring Sanctum test setup).

Reviewed changes

Copilot reviewed 37 out of 37 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
tests/Testbench/TestCaseTest.php Adds coverage that the new Testbench TestCase composes the expected traits and applies attributes/hooks.
tests/Testbench/Concerns/HandlesRoutesWithoutWebRoutesTest.php Verifies API routes work when defineWebRoutes() is not overridden.
tests/Testbench/Concerns/HandlesRoutesTest.php Verifies defineRoutes() / defineWebRoutes() are executed and routes are reachable.
tests/Testbench/Concerns/CreatesApplicationTest.php Verifies package providers/aliases hooks work for package testing.
tests/Sentry/Features/LogFeatureTest.php Updates defineEnvironment() signature to the new typed hook.
tests/Sanctum/AuthenticateRequestsTest.php Refactors test setup to use Testbench hooks (getPackageProviders, defineEnvironment, defineRoutes).
tests/Foundation/Testing/Concerns/InteractsWithTestCaseTest.php Adds tests for trait caching and attribute parsing/execution behavior.
tests/Foundation/Testing/Concerns/HandlesAttributesTest.php Adds coverage for parsing/executing method attributes via the concern.
tests/Foundation/Testing/Concerns/DefineEnvironmentTest.php Verifies defineEnvironment() hook is invoked during setup and can mutate config.
tests/Foundation/Testing/Concerns/AttributeInheritanceTest.php Verifies attribute inheritance from parent test case classes.
tests/Foundation/Testing/Attributes/AttributesTest.php Adds coverage for attribute contracts/targets and attribute behaviors.
src/testbench/src/TestCase.php Integrates new Testbench traits and coroutine-aware lifecycle execution into the base Testbench test case.
src/testbench/src/Concerns/HandlesRoutes.php Adds defineRoutes / defineWebRoutes hooks and automatic application route setup.
src/testbench/src/Concerns/HandlesDatabases.php Adds migration/seeder hook structure and a setUpDatabaseRequirements() helper.
src/testbench/src/Concerns/CreatesApplication.php Adds package provider/alias hook APIs and registration helpers.
src/foundation/src/Testing/Features/TestingFeature.php Adds an orchestrator intended to coordinate default vs attribute-based feature execution.
src/foundation/src/Testing/Features/FeaturesCollection.php Adds a collection type to manage and execute deferred feature callbacks.
src/foundation/src/Testing/Contracts/Attributes/TestingFeature.php Adds a marker interface for test feature attributes.
src/foundation/src/Testing/Contracts/Attributes/Resolvable.php Adds a contract for meta-attributes that resolve into concrete attributes.
src/foundation/src/Testing/Contracts/Attributes/Invokable.php Adds a contract for directly invokable attributes (e.g., WithConfig).
src/foundation/src/Testing/Contracts/Attributes/BeforeEach.php Adds lifecycle contract for “before each test” attributes.
src/foundation/src/Testing/Contracts/Attributes/BeforeAll.php Adds lifecycle contract for “before all tests in class” attributes.
src/foundation/src/Testing/Contracts/Attributes/AfterEach.php Adds lifecycle contract for “after each test” attributes.
src/foundation/src/Testing/Contracts/Attributes/AfterAll.php Adds lifecycle contract for “after all tests in class” attributes.
src/foundation/src/Testing/Contracts/Attributes/Actionable.php Adds contract for attributes that dispatch method execution via a callback.
src/foundation/src/Testing/Concerns/InteractsWithTestCase.php Adds attribute caching plus lifecycle execution (Before/After Each/All) for PHPUnit test cases.
src/foundation/src/Testing/Concerns/InteractsWithContainer.php Adds and invokes the defineEnvironment() hook during application refresh.
src/foundation/src/Testing/Concerns/HandlesAttributes.php Adds an internal API for parsing/executing attributes of a specific type.
src/foundation/src/Testing/Attributes/WithMigration.php Adds attribute to register migration paths via the Migrator.
src/foundation/src/Testing/Attributes/WithConfig.php Adds attribute to set config key/value pairs.
src/foundation/src/Testing/Attributes/ResetRefreshDatabaseState.php Adds attribute to reset RefreshDatabaseState before/after a test class.
src/foundation/src/Testing/Attributes/RequiresEnv.php Adds attribute to skip tests when required environment variables are missing.
src/foundation/src/Testing/Attributes/DefineRoute.php Adds attribute to invoke a route-definition method with the Router.
src/foundation/src/Testing/Attributes/DefineEnvironment.php Adds attribute to invoke an environment-definition method with the app container.
src/foundation/src/Testing/Attributes/DefineDatabase.php Adds attribute to invoke database setup methods with deferred execution support.
src/foundation/src/Testing/Attributes/Define.php Adds meta-attribute resolving shorthand (env/db/route) to concrete attributes.
src/foundation/src/Testing/AttributeParser.php Adds parser to collect (and resolve) testing-related attributes from classes/methods.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- Fix usesTestingFeature test to use TARGET_METHOD flag to avoid
  class-level feature persistence affecting other tests
- Fix PHPDoc return type in HandlesAttributes to correctly reflect
  Collection<Collection> instead of Collection<array>
- Fix deferred Actionable attributes (like DefineDatabase with defer:true)
  by capturing and executing returned closures in setUpTheTestEnvironmentUsingTestCase
- Add tests for deferred attribute execution and return type validation
This class was ported from Orchestra Testbench but never integrated.
It was dead code that was never imported or called anywhere.
@albertcht albertcht merged commit 25e27eb into hypervel:main Jan 26, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants