diff --git a/composer.json b/composer.json index 076b128..d63242d 100644 --- a/composer.json +++ b/composer.json @@ -44,22 +44,22 @@ "nyholm/psr7": "^1.5", "mockery/mockery": "^1.5", "phpunit/phpunit": "^9.6 || ^10.0", - "spiral/auth": "^3.12", - "spiral/auth-http": "^3.12", - "spiral/boot": "^3.12", - "spiral/events": "^3.12", - "spiral/console": "^3.12", - "spiral/core": "^3.12", - "spiral/http": "^3.12", - "spiral/mailer": "^3.12", - "spiral/queue": "^3.12", - "spiral/session": "^3.12", - "spiral/security": "^3.12", - "spiral/tokenizer": "^3.12", - "spiral/storage": "^3.12", - "spiral/views": "^3.12", - "spiral/translator": "^3.12", - "spiral/scaffolder": "^3.12", + "spiral/auth": "^3.14.3", + "spiral/auth-http": "^3.14.3", + "spiral/boot": "^3.14.3", + "spiral/events": "^3.14.3", + "spiral/console": "^3.14.3", + "spiral/core": "^3.14.3", + "spiral/http": "^3.14.3", + "spiral/mailer": "^3.14.3", + "spiral/queue": "^3.14.3", + "spiral/session": "^3.14.3", + "spiral/security": "^3.14.3", + "spiral/tokenizer": "^3.14.3", + "spiral/storage": "^3.14.3", + "spiral/views": "^3.14.3", + "spiral/translator": "^3.14.3", + "spiral/scaffolder": "^3.14.3", "symfony/mime": "^6.0 || ^7.0" }, "suggest": { @@ -67,10 +67,11 @@ "ext-gd": "Required to use generate fake image files" }, "require-dev": { - "spiral/framework": "^3.12", - "spiral/roadrunner-bridge": "^2.2 || ^3.0", + "spiral/dumper": "^3.3", + "spiral/framework": "^3.14.3", + "spiral/roadrunner-bridge": "^2.2 || ^3.7 || ^4.0", "spiral-packages/league-event": "^1.0.1", - "spiral/nyholm-bridge": "^1.2", + "spiral/nyholm-bridge": "^1.3", "vimeo/psalm": "^5.9" }, "autoload": { diff --git a/src/Http/FakeHttp.php b/src/Http/FakeHttp.php index a8b32bd..e0ea6d3 100644 --- a/src/Http/FakeHttp.php +++ b/src/Http/FakeHttp.php @@ -37,6 +37,9 @@ class FakeHttp private ?SessionInterface $session = null; private BinderInterface $binder; + /** + * @param \Closure(\Closure $closure, array $bindings): mixed $scope Scope runner + */ public function __construct( #[Proxy] private readonly ContainerInterface $container, private readonly FileFactory $fileFactory, @@ -418,9 +421,7 @@ protected function handleRequest(ServerRequestInterface $request, array $binding return $this->getHttp()->handle($request); }; - $scope = $this->scope; - - return new TestResponse($scope($handler, $bindings)); + return new TestResponse(($this->scope)($handler, $bindings)); } protected function validateRequestData($data): void diff --git a/src/TestCase.php b/src/TestCase.php index 41dd871..570c860 100644 --- a/src/TestCase.php +++ b/src/TestCase.php @@ -14,6 +14,7 @@ use Spiral\Core\ConfigsInterface; use Spiral\Core\Container; use Spiral\Core\ContainerScope; +use Spiral\Core\Internal\Introspector; use Spiral\Core\Scope; use Spiral\Testing\Attribute\TestScope; @@ -173,7 +174,7 @@ public function initApp(array $env = [], Container $container = new Container()) * @param array $bindings * @throws \Throwable */ - public function runScoped(Closure $callback, array $bindings = []): mixed + public function runScoped(Closure $callback, array $bindings = [], ?string $name = null): mixed { if ($this->environment) { $bindings[EnvironmentInterface::class] = $this->environment; @@ -234,7 +235,7 @@ protected function runTest(): mixed } $scopes = \is_array($scope->scope) ? $scope->scope : [$scope->scope]; - $result = $this->runScopes($scopes, function (): mixed { + $result = self::runScopes($scopes, function (): mixed { return parent::runTest(); }, $this->getContainer(), $scope->bindings); @@ -280,18 +281,23 @@ private function getTestScope(): ?TestScope return null; } - private function runScopes(array $scopes, Closure $callback, Container $container, array $bindings): mixed + private static function runScopes(array $scopes, Closure $callback, Container $container, array $bindings): mixed { + begin: if ($scopes === []) { return $container->runScope($bindings, $callback); } + $scope = \array_shift($scopes); + if ($scopes !== null && \in_array($scope, Introspector::scopeNames(), true)) { + goto begin; + } return $container->runScope( new Scope($scope, []), function (Container $container) use ($scopes, $callback, $bindings): mixed { - return $this->runScopes($scopes, $callback, $container, $bindings); + return self::runScopes($scopes, $callback, $container, $bindings); }, ); } diff --git a/src/Traits/InteractsWithHttp.php b/src/Traits/InteractsWithHttp.php index d0a02e0..beea671 100644 --- a/src/Traits/InteractsWithHttp.php +++ b/src/Traits/InteractsWithHttp.php @@ -20,7 +20,7 @@ final public function fakeHttp(): FakeHttp return $this->getContainer()->get(FactoryInterface::class)->make(FakeHttp::class, [ 'fileFactory' => $this->getFileFactory(), 'scope' => function (\Closure $closure, array $bindings = []) { - return $this->runScoped($closure, $bindings); + return self::runScopes(['http'], $closure, $this->getContainer(), $bindings); } ]); } diff --git a/tests/app/Controller/GetController.php b/tests/app/Controller/GetController.php index 04f68fd..265b5d8 100644 --- a/tests/app/Controller/GetController.php +++ b/tests/app/Controller/GetController.php @@ -5,6 +5,7 @@ namespace Spiral\Testing\Tests\App\Controller; use Psr\Http\Message\ServerRequestInterface; +use Spiral\Core\Internal\Introspector; use Spiral\Router\Annotation\Route; class GetController @@ -20,4 +21,10 @@ public function headers(ServerRequestInterface $request): array { return $request->getHeaders(); } + + #[Route('/get/scopes', 'get.scopes')] + public function scopes(ServerRequestInterface $request): array + { + return Introspector::scopeNames(); + } } diff --git a/tests/src/Event/EventDispatcherTest.php b/tests/src/Event/EventDispatcherTest.php index f96e4c8..9df6060 100644 --- a/tests/src/Event/EventDispatcherTest.php +++ b/tests/src/Event/EventDispatcherTest.php @@ -4,6 +4,7 @@ namespace Spiral\Testing\Tests\Event; +use PHPUnit\Framework\Attributes\RunInSeparateProcess; use PHPUnit\Framework\ExpectationFailedException; use Spiral\Testing\Events\FakeEventDispatcher; use Spiral\Testing\Tests\App\Event\AnotherEvent; @@ -78,7 +79,7 @@ public function testAssertNotDispatchedSomeEventShouldThrowAnException(): void public function testAssertNothingDispatchedShouldThrowAnException(): void { $this->expectException(ExpectationFailedException::class); - $this->expectExceptionMessage('3 unexpected events were dispatched.'); + $this->expectExceptionMessageMatches('/\d+ unexpected events were dispatched./'); $this->http->get('/dispatch/some'); diff --git a/tests/src/Http/FakeHttpTest.php b/tests/src/Http/FakeHttpTest.php index 255ff1a..cded893 100644 --- a/tests/src/Http/FakeHttpTest.php +++ b/tests/src/Http/FakeHttpTest.php @@ -17,6 +17,19 @@ public function testGetBodySame(): void $response->assertBodySame('[]'); } + #[TestScope('http')] + public function testHttpScopeDoesNotConflict(): void + { + $response = $this->fakeHttp()->get('/get/query-params'); + $response->assertBodySame('[]'); + } + + public function testAutoHttpScope(): void + { + $response = $this->fakeHttp()->get('/get/scopes'); + $response->assertBodySame('["http-request","http","root"]'); + } + public function testGetWithQueryParams(): void { $response = $this->fakeHttp()->get('/get/query-params', ['foo' => 'bar', 'baz' => ['foo1' => 'bar1']]);