diff --git a/src/Testing/AssertableInertia.php b/src/Testing/AssertableInertia.php index d1ee90e7..1be7cd6a 100644 --- a/src/Testing/AssertableInertia.php +++ b/src/Testing/AssertableInertia.php @@ -2,6 +2,7 @@ namespace Inertia\Testing; +use Closure; use Illuminate\Testing\Fluent\AssertableJson; use Illuminate\Testing\TestResponse; use InvalidArgumentException; @@ -81,6 +82,69 @@ public function version(string $value): self return $this; } + /** + * Reload the Inertia page and perform assertions on the response. + */ + public function reload(?Closure $callback = null, array|string|null $only = null, array|string|null $except = null): self + { + if (is_array($only)) { + $only = implode(',', $only); + } + + if (is_array($except)) { + $except = implode(',', $except); + } + + $reloadRequest = new ReloadRequest( + $this->url, + $this->component, + $this->version, + $only, + $except, + ); + + $assertable = AssertableInertia::fromTestResponse($reloadRequest()); + + // Make sure we get the same data as the original request. + $assertable->component($this->component); + $assertable->url($this->url); + $assertable->version($this->version); + + if ($callback) { + $callback($assertable); + } + + return $this; + } + + /** + * Reload the Inertia page as a partial request with only the specified props. + */ + public function reloadOnly(array|string $only, ?Closure $callback = null): self + { + return $this->reload(only: $only, callback: function (AssertableInertia $assertable) use ($only, $callback) { + $assertable->hasAll(explode(',', $only)); + + if ($callback) { + $callback($assertable); + } + }); + } + + /** + * Reload the Inertia page as a partial request excluding the specified props. + */ + public function reloadExcept(array|string $except, ?Closure $callback = null): self + { + return $this->reload(except: $except, callback: function (AssertableInertia $assertable) use ($except, $callback) { + $assertable->missingAll(explode(',', $except)); + + if ($callback) { + $callback($assertable); + } + }); + } + public function toArray() { return [ diff --git a/src/Testing/ReloadRequest.php b/src/Testing/ReloadRequest.php new file mode 100644 index 00000000..789962dd --- /dev/null +++ b/src/Testing/ReloadRequest.php @@ -0,0 +1,47 @@ +app ??= app(); + } + + /** + * Request the Inertia page as a partial reload. + */ + public function __invoke(): TestResponse + { + $headers = [Header::VERSION => $this->version]; + + if (! blank($this->only)) { + $headers[Header::PARTIAL_COMPONENT] = $this->component; + $headers[Header::PARTIAL_ONLY] = $this->only; + } + + if (! blank($this->except)) { + $headers[Header::PARTIAL_COMPONENT] = $this->component; + $headers[Header::PARTIAL_EXCEPT] = $this->except; + } + + return $this->get($this->url, $headers); + } +} diff --git a/tests/TestCase.php b/tests/TestCase.php index 8de5be0f..b3f6e237 100644 --- a/tests/TestCase.php +++ b/tests/TestCase.php @@ -52,7 +52,7 @@ protected function getTestResponseClass(): string protected function makeMockRequest($view) { app('router')->get('/example-url', function () use ($view) { - return $view; + return is_callable($view) ? $view() : $view; }); return $this->get('/example-url'); diff --git a/tests/Testing/AssertableInertiaTest.php b/tests/Testing/AssertableInertiaTest.php index 913b7e1e..2d385034 100644 --- a/tests/Testing/AssertableInertiaTest.php +++ b/tests/Testing/AssertableInertiaTest.php @@ -3,6 +3,7 @@ namespace Inertia\Tests\Testing; use Inertia\Inertia; +use Inertia\Testing\AssertableInertia; use Inertia\Tests\TestCase; use PHPUnit\Framework\AssertionFailedError; @@ -193,4 +194,86 @@ public function test_the_asset_version_does_not_match(): void $inertia->version('different-version'); }); } + + public function test_reloading_a_visit(): void + { + $foo = 0; + + $response = $this->makeMockRequest(function () use (&$foo) { + return Inertia::render('foo', [ + 'foo' => $foo++, + ]); + }); + + $called = false; + + $response->assertInertia(function ($inertia) use (&$called) { + $inertia->where('foo', 0); + + $inertia->reload(function ($inertia) use (&$called) { + $inertia->where('foo', 1); + $called = true; + }); + }); + + $this->assertTrue($called); + } + + public function test_lazy_props_can_be_evaluated(): void + { + $response = $this->makeMockRequest( + Inertia::render('foo', [ + 'foo' => 'bar', + 'lazy1' => Inertia::lazy(fn () => 'baz'), + 'lazy2' => Inertia::lazy(fn () => 'qux'), + ]) + ); + + $called = false; + + $response->assertInertia(function ($inertia) use (&$called) { + $inertia->where('foo', 'bar'); + $inertia->missing('lazy1'); + $inertia->missing('lazy2'); + + $result = $inertia->reloadOnly('lazy1', function ($inertia) use (&$called) { + $inertia->missing('foo'); + $inertia->where('lazy1', 'baz'); + $inertia->missing('lazy2'); + $called = true; + }); + + $this->assertSame($result, $inertia); + }); + + $this->assertTrue($called); + } + + public function test_lazy_props_can_be_evaluated_with_except(): void + { + $response = $this->makeMockRequest( + Inertia::render('foo', [ + 'foo' => 'bar', + 'lazy1' => Inertia::lazy(fn () => 'baz'), + 'lazy2' => Inertia::lazy(fn () => 'qux'), + ]) + ); + + $called = false; + + $response->assertInertia(function (AssertableInertia $inertia) use (&$called) { + $inertia->where('foo', 'bar'); + $inertia->missing('lazy1'); + $inertia->missing('lazy2'); + + $inertia->reloadExcept('lazy1', function ($inertia) use (&$called) { + $inertia->where('foo', 'bar'); + $inertia->missing('lazy1'); + $inertia->where('lazy2', 'qux'); + $called = true; + }); + }); + + $this->assertTrue($called); + } }