diff --git a/src/ServiceProvider.php b/src/ServiceProvider.php index 35f651b8..91da8676 100644 --- a/src/ServiceProvider.php +++ b/src/ServiceProvider.php @@ -2,6 +2,8 @@ namespace Inertia; +use Illuminate\Contracts\Events\Dispatcher; +use Illuminate\Foundation\Http\Events\RequestHandled; use LogicException; use Inertia\Ssr\Gateway; use ReflectionException; @@ -13,6 +15,7 @@ use Inertia\Testing\TestResponseMacros; use Illuminate\Support\ServiceProvider as BaseServiceProvider; use Illuminate\Foundation\Testing\TestResponse as LegacyTestResponse; +use Inertia\Testing\Listeners\RequestHandledListener; class ServiceProvider extends BaseServiceProvider { @@ -38,6 +41,10 @@ public function register(): void $app['config']->get('inertia.testing.page_extensions') ); }); + + $this->app->bind('inertia.testing.request', function ($app) { + return null; + }); } public function boot(): void @@ -47,6 +54,11 @@ public function boot(): void $this->publishes([ __DIR__.'/../config/inertia.php' => config_path('inertia.php'), ]); + + if (app()->environment('testing') === true) { + $dispatcher = app(Dispatcher::class); + $dispatcher->listen(RequestHandled::class, RequestHandledListener::class); + } } protected function registerBladeDirectives(): void diff --git a/src/Testing/Assert.php b/src/Testing/Assert.php index 903a6086..e4bc1a1d 100644 --- a/src/Testing/Assert.php +++ b/src/Testing/Assert.php @@ -4,6 +4,9 @@ use Closure; use const E_USER_DEPRECATED; +use Illuminate\Contracts\Http\Kernel; +use Illuminate\Testing\TestResponse; +use Illuminate\Foundation\Testing\TestResponse as LegacyTestResponse; use Illuminate\Support\Traits\Macroable; use PHPUnit\Framework\Assert as PHPUnit; use Illuminate\Contracts\Support\Arrayable; @@ -89,4 +92,39 @@ public static function fromTestResponse($response): self return new self($page['component'], $page['props'], $page['url'], $page['version']); } + + public function requestProp(string $prop, Closure $assert = null): self + { + $request = app('inertia.testing.request'); + if ($request === null) { + PHPUnit::fail('Unable to catch the previous request via the `\Illuminate\Foundation\Http\Events\RequestHandled` event using listener. If you are using Event::fake(), please use Event::fakeExcept(RequestHandled::class) instead when calling requestProp if you want to block other events.'); + } + + $request->headers->add([ + 'X-Inertia-Partial-Component' => $this->component, + 'X-Inertia-Partial-Data' => $prop, + ]); + + + $kernel = app()->make(Kernel::class); + $response = $kernel->handle($request); + + $kernel->terminate($request, $response); + + $testResponseClass = TestResponse::class; + if (class_exists($testResponseClass) == false) { + $testResponseClass = LegacyTestResponse::class; + } + + $testResponse = $testResponseClass::fromBaseResponse($response); + $testResponse->assertInertia(function (Assert $page) use ($prop, $assert) { + $page->has($prop); + + if ($assert !== null) { + $assert($page); + } + }); + + return $this; + } } diff --git a/src/Testing/AssertableInertia.php b/src/Testing/AssertableInertia.php index 370e748d..fbe4fa81 100644 --- a/src/Testing/AssertableInertia.php +++ b/src/Testing/AssertableInertia.php @@ -3,6 +3,10 @@ namespace Inertia\Testing; use InvalidArgumentException; +use Closure; +use Illuminate\Contracts\Http\Kernel; +use Illuminate\Support\Facades\Event; +use Illuminate\Support\Testing\Fakes\Fake; use Illuminate\Testing\TestResponse; use PHPUnit\Framework\Assert as PHPUnit; use PHPUnit\Framework\AssertionFailedError; @@ -71,6 +75,40 @@ public function version(string $value): self return $this; } + public function requestProp(string $prop, Closure $assert = null): self + { + $request = app('inertia.testing.request'); + if ($request === null) { + if (Event::getFacadeRoot() instanceof Fake) { + PHPUnit::fail('Unable to listen to the `\Illuminate\Foundation\Http\Events\RequestHandled` event. Please use Event::fakeExcept(RequestHandled::class) when using requestProp if you want to block other events.'); + } + + PHPUnit::fail('Unable to catch the previous request via the `\Illuminate\Foundation\Http\Events\RequestHandled` event using listener.'); + } + + $request->headers->add([ + 'X-Inertia-Partial-Component' => $this->component, + 'X-Inertia-Partial-Data' => $prop, + ]); + + + $kernel = app()->make(Kernel::class); + $response = $kernel->handle($request); + + $kernel->terminate($request, $response); + + $testResponse = TestResponse::fromBaseResponse($response); + $testResponse->assertInertia(function (AssertableInertia $page) use ($prop, $assert) { + $page->has($prop); + + if($assert !== null){ + $assert($page); + } + }); + + return $this; + } + public function toArray() { return [ diff --git a/src/Testing/Listeners/RequestHandledListener.php b/src/Testing/Listeners/RequestHandledListener.php new file mode 100644 index 00000000..85fe4edd --- /dev/null +++ b/src/Testing/Listeners/RequestHandledListener.php @@ -0,0 +1,15 @@ +bind('inertia.testing.request', function () use ($event) { + return $event->request; + }); + } +} diff --git a/tests/Testing/AssertableInertiaTest.php b/tests/Testing/AssertableInertiaTest.php index 613cccc2..3eb89cec 100644 --- a/tests/Testing/AssertableInertiaTest.php +++ b/tests/Testing/AssertableInertiaTest.php @@ -207,4 +207,37 @@ public function the_asset_version_does_not_match(): void $inertia->version('different-version'); }); } + + /** @test */ + public function the_lazy_prop_can_be_fetch_via_the_request_prop_method(): void + { + $response = $this->makeMockRequest( + Inertia::render('foo', [ + 'bar' => Inertia::lazy(function () { + return 'foobar'; + }), + ]) + ); + $response->assertInertia(function ($inertia) { + $inertia->missing('bar'); + + $inertia->requestProp('bar', function ($subInertia) { + $subInertia->where('bar', 'foobar'); + }); + }); + } + + /** @test */ + public function the_request_prop_method_fails_if_prop_does_not_exists(): void + { + $response = $this->makeMockRequest( + Inertia::render('foo') + ); + + $this->expectException(AssertionFailedError::class); + + $response->assertInertia(function ($inertia) { + $inertia->requestProp('bar'); + }); + } } diff --git a/tests/Testing/Listeners/RequestHandledListener.php b/tests/Testing/Listeners/RequestHandledListener.php new file mode 100644 index 00000000..7cb043bb --- /dev/null +++ b/tests/Testing/Listeners/RequestHandledListener.php @@ -0,0 +1,25 @@ +assertNull(app('inertia.testing.request')); + + Event::dispatch(new RequestHandled($request, $response)); + + $this->assertSame($request, app('inertia.testing.request')); + } +}