From 295827f1ab2020d867d0748b6298fc08f6a35fa2 Mon Sep 17 00:00:00 2001 From: antoine Date: Fri, 9 Jan 2026 17:41:09 +0100 Subject: [PATCH] wip new testing API --- .../EntityList/AssertableEntityList.php | 19 +++++ .../Testing/EntityList/PendingEntityList.php | 53 +++++++++++++ src/Utils/Testing/GeneratesSharpUrl.php | 64 ++++++++++++++++ src/Utils/Testing/SharpAssertions.php | 76 +++++-------------- .../Utils/Testing/SharpAssertionsTest.php | 59 +++++++++++++- 5 files changed, 210 insertions(+), 61 deletions(-) create mode 100644 src/Utils/Testing/EntityList/AssertableEntityList.php create mode 100644 src/Utils/Testing/EntityList/PendingEntityList.php create mode 100644 src/Utils/Testing/GeneratesSharpUrl.php diff --git a/src/Utils/Testing/EntityList/AssertableEntityList.php b/src/Utils/Testing/EntityList/AssertableEntityList.php new file mode 100644 index 000000000..fd14249ea --- /dev/null +++ b/src/Utils/Testing/EntityList/AssertableEntityList.php @@ -0,0 +1,19 @@ +response->assertOk(); + + return $this; + } +} diff --git a/src/Utils/Testing/EntityList/PendingEntityList.php b/src/Utils/Testing/EntityList/PendingEntityList.php new file mode 100644 index 000000000..f1a4dc0ea --- /dev/null +++ b/src/Utils/Testing/EntityList/PendingEntityList.php @@ -0,0 +1,53 @@ +entityKeyFor($this->entityKey); + $this->entityList = app(SharpEntityManager::class)->entityFor($resolvedEntityKey)->getListOrFail(); + } + + public function withFilter(string $filterKey, mixed $value): static + { + $key = $this->entityList->filterContainer()->findFilterHandler($filterKey)->getKey(); + $this->filterValues[$key] = $value; + + return $this; + } + + public function get(): AssertableEntityList + { + $this->setGlobalFilterUrlDefault(); + + return new AssertableEntityList( + $this->test->get( + route('code16.sharp.list', [ + 'entityKey' => $this->entityKey, + ...$this->entityList + ->filterContainer() + ->getQueryParamsFromFilterValues($this->filterValues), + ]) + ) + ); + } + + public function callInstanceCommand() {} + + public function callEntityCommand() {} +} diff --git a/src/Utils/Testing/GeneratesSharpUrl.php b/src/Utils/Testing/GeneratesSharpUrl.php new file mode 100644 index 000000000..6fb632bdf --- /dev/null +++ b/src/Utils/Testing/GeneratesSharpUrl.php @@ -0,0 +1,64 @@ +breadcrumbBuilder = $callback(new BreadcrumbBuilder()); + + return $this; + } + + public function withSharpGlobalFilterValues(array|string $globalFilterValues): self + { + $this->globalFilter = collect((array) $globalFilterValues) + ->implode(GlobalFilters::$valuesUrlSeparator); + + return $this; + } + + private function setGlobalFilterUrlDefault(): void + { + URL::defaults(['globalFilter' => $this->globalFilter ?: GlobalFilters::$defaultKey]); + } + + private function breadcrumbBuilder(string $entityKey, ?string $instanceId = null): BreadcrumbBuilder + { + if (isset($this->breadcrumbBuilder)) { + return $this->breadcrumbBuilder; + } + + return (new BreadcrumbBuilder()) + ->appendEntityList($entityKey) + ->when($instanceId, fn ($builder) => $builder->appendShowPage($entityKey, $instanceId)); + } + + private function buildCurrentPageUrl(BreadcrumbBuilder $builder): string + { + return url( + sprintf( + '/%s/%s/%s', + sharp()->config()->get('custom_url_segment'), + sharp()->context()->globalFilterUrlSegmentValue(), + $builder->generateUri() + ) + ); + } +} diff --git a/src/Utils/Testing/SharpAssertions.php b/src/Utils/Testing/SharpAssertions.php index 1e1bf980b..a22318763 100644 --- a/src/Utils/Testing/SharpAssertions.php +++ b/src/Utils/Testing/SharpAssertions.php @@ -2,17 +2,19 @@ namespace Code16\Sharp\Utils\Testing; -use Closure; -use Code16\Sharp\Filters\GlobalFilters\GlobalFilters; use Code16\Sharp\Http\Context\SharpBreadcrumb; use Code16\Sharp\Utils\Entities\SharpEntityManager; use Code16\Sharp\Utils\Links\BreadcrumbBuilder; -use Illuminate\Support\Facades\URL; +use Code16\Sharp\Utils\Testing\EntityList\PendingEntityList; trait SharpAssertions { - private BreadcrumbBuilder $breadcrumbBuilder; - private ?string $globalFilter = null; + use GeneratesSharpUrl; + + public function sharpList(string $entityClassNameOrKey): PendingEntityList + { + return new PendingEntityList($this, $entityClassNameOrKey); + } /** * @deprecated use withSharpBreadcrumb() instead @@ -32,28 +34,9 @@ public function withSharpCurrentBreadcrumb(...$breadcrumb): self return $this; } - /** - * @param (\Closure(BreadcrumbBuilder): BreadcrumbBuilder) $callback - * @return $this - */ - public function withSharpBreadcrumb(Closure $callback): self - { - $this->breadcrumbBuilder = $callback(new BreadcrumbBuilder()); - - return $this; - } - - public function withSharpGlobalFilterValues(array|string $globalFilterValues): self - { - $this->globalFilter = collect((array) $globalFilterValues) - ->implode(GlobalFilters::$valuesUrlSeparator); - - return $this; - } - public function deleteFromSharpShow(string $entityClassNameOrKey, mixed $instanceId) { - URL::defaults(['globalFilter' => $this->globalFilter ?: GlobalFilters::$defaultKey]); + $this->setGlobalFilterUrlDefault(); $entityKey = $this->resolveEntityKey($entityClassNameOrKey); @@ -72,7 +55,7 @@ public function deleteFromSharpShow(string $entityClassNameOrKey, mixed $instanc public function deleteFromSharpList(string $entityClassNameOrKey, mixed $instanceId) { - URL::defaults(['globalFilter' => $this->globalFilter ?: GlobalFilters::$defaultKey]); + $this->setGlobalFilterUrlDefault(); $entityKey = $this->resolveEntityKey($entityClassNameOrKey); @@ -94,7 +77,7 @@ public function deleteFromSharpList(string $entityClassNameOrKey, mixed $instanc public function getSharpForm(string $entityClassNameOrKey, mixed $instanceId = null) { - URL::defaults(['globalFilter' => $this->globalFilter ?: GlobalFilters::$defaultKey]); + $this->setGlobalFilterUrlDefault(); $entityKey = $this->resolveEntityKey($entityClassNameOrKey); @@ -123,7 +106,7 @@ public function getSharpForm(string $entityClassNameOrKey, mixed $instanceId = n public function getSharpSingleForm(string $entityClassNameOrKey) { - URL::defaults(['globalFilter' => $this->globalFilter ?: GlobalFilters::$defaultKey]); + $this->setGlobalFilterUrlDefault(); $entityKey = $this->resolveEntityKey($entityClassNameOrKey); @@ -142,7 +125,7 @@ public function getSharpSingleForm(string $entityClassNameOrKey) public function updateSharpForm(string $entityClassNameOrKey, $instanceId, array $data) { - URL::defaults(['globalFilter' => $this->globalFilter ?: GlobalFilters::$defaultKey]); + $this->setGlobalFilterUrlDefault(); $entityKey = $this->resolveEntityKey($entityClassNameOrKey); @@ -162,7 +145,7 @@ public function updateSharpForm(string $entityClassNameOrKey, $instanceId, array public function updateSharpSingleForm(string $entityClassNameOrKey, array $data) { - URL::defaults(['globalFilter' => $this->globalFilter ?: GlobalFilters::$defaultKey]); + $this->setGlobalFilterUrlDefault(); $entityKey = $this->resolveEntityKey($entityClassNameOrKey); @@ -181,7 +164,7 @@ public function updateSharpSingleForm(string $entityClassNameOrKey, array $data) public function getSharpShow(string $entityClassNameOrKey, $instanceId) { - URL::defaults(['globalFilter' => $this->globalFilter ?: GlobalFilters::$defaultKey]); + $this->setGlobalFilterUrlDefault(); $entityKey = $this->resolveEntityKey($entityClassNameOrKey); @@ -201,7 +184,7 @@ public function getSharpShow(string $entityClassNameOrKey, $instanceId) public function storeSharpForm(string $entityClassNameOrKey, array $data) { - URL::defaults(['globalFilter' => $this->globalFilter ?: GlobalFilters::$defaultKey]); + $this->setGlobalFilterUrlDefault(); $entityKey = $this->resolveEntityKey($entityClassNameOrKey); @@ -226,7 +209,7 @@ public function callSharpInstanceCommandFromList( array $data = [], ?string $commandStep = null ) { - URL::defaults(['globalFilter' => $this->globalFilter ?: GlobalFilters::$defaultKey]); + $this->setGlobalFilterUrlDefault(); $entityKey = $this->resolveEntityKey($entityClassNameOrKey); @@ -257,7 +240,7 @@ public function callSharpInstanceCommandFromShow( array $data = [], ?string $commandStep = null ) { - URL::defaults(['globalFilter' => $this->globalFilter ?: GlobalFilters::$defaultKey]); + $this->setGlobalFilterUrlDefault(); $entityKey = $this->resolveEntityKey($entityClassNameOrKey); @@ -287,7 +270,7 @@ public function callSharpEntityCommandFromList( array $data = [], ?string $commandStep = null ) { - URL::defaults(['globalFilter' => $this->globalFilter ?: GlobalFilters::$defaultKey]); + $this->setGlobalFilterUrlDefault(); $entityKey = $this->resolveEntityKey($entityClassNameOrKey); @@ -311,29 +294,6 @@ public function loginAsSharpUser($user): self return $this->actingAs($user, sharp()->config()->get('auth.guard') ?: config('auth.defaults.guard')); } - private function breadcrumbBuilder(string $entityKey, ?string $instanceId = null): BreadcrumbBuilder - { - if (isset($this->breadcrumbBuilder)) { - return $this->breadcrumbBuilder; - } - - return (new BreadcrumbBuilder()) - ->appendEntityList($entityKey) - ->when($instanceId, fn ($builder) => $builder->appendShowPage($entityKey, $instanceId)); - } - - private function buildCurrentPageUrl(BreadcrumbBuilder $builder): string - { - return url( - sprintf( - '/%s/%s/%s', - sharp()->config()->get('custom_url_segment'), - sharp()->context()->globalFilterUrlSegmentValue(), - $builder->generateUri() - ) - ); - } - private function resolveEntityKey(string $entityClassNameOrKey): string { return app(SharpEntityManager::class)->entityKeyFor($entityClassNameOrKey); diff --git a/tests/Unit/Utils/Testing/SharpAssertionsTest.php b/tests/Unit/Utils/Testing/SharpAssertionsTest.php index 64b2fc166..a317e0c81 100644 --- a/tests/Unit/Utils/Testing/SharpAssertionsTest.php +++ b/tests/Unit/Utils/Testing/SharpAssertionsTest.php @@ -1,9 +1,55 @@ config()->declareEntity(PersonEntity::class); +}); + +it('allows to test entity list', function () { + fakeListFor(PersonEntity::class, new class() extends PersonList + { + public function getFilters(): ?array + { + return [ + new class() extends SelectFilter + { + public function buildFilterConfig(): void + { + $this->configureKey('job'); + } + + public function values(): array + { + return [ + 'physicist' => 'Physicist', + 'physician' => 'Physician', + ]; + } + }, + ]; + } + }); + + $response = fakeResponse(); + $response->sharpList('person') + ->withFilter('job', 'physicist') + ->get(); + + expect($response->uri)->toEqual( + route('code16.sharp.list', [ + 'entityKey' => 'person', + 'filter_job' => 'physicist', + ]) + ); +}); + it('allows to test getSharpShow', function () { $response = fakeResponse()->getSharpShow('leaves', 6); @@ -249,9 +295,10 @@ function fakeResponse() return new class('fake') extends Orchestra\Testbench\TestCase { use SharpAssertions; + use Tappable; - public $uri; - public $postedData; + public string $uri; + public mixed $postedData; public function call($method, $uri, $parameters = [], $cookies = [], $files = [], $server = [], $content = null) { @@ -265,7 +312,13 @@ public function call($method, $uri, $parameters = [], $cookies = [], $files = [] $this->postedData = null; } - return $this; + return new class($this->uri, $this->postedData) extends \Illuminate\Testing\TestResponse + { + public function __construct(public $uri, public $postedData) + { + parent::__construct(new \Illuminate\Http\Response()); + } + }; } }; }