diff --git a/src/Utils/Testing/Commands/AssertableCommand.php b/src/Utils/Testing/Commands/AssertableCommand.php new file mode 100644 index 000000000..ab8570f30 --- /dev/null +++ b/src/Utils/Testing/Commands/AssertableCommand.php @@ -0,0 +1,71 @@ +response->assertJson(fn (AssertableJson $json) => $json->where('action', 'html') + ); + + return $this; + } + + public function assertReturnsInfo(string $message = ''): static + { + $this->response->assertJson(fn (AssertableJson $json) => $json->where('action', 'info') + ->when($message)->where('message', $message) + ->etc() + ); + + return $this; + } + + public function assertReturnsLink(string $url = ''): static + { + $this->response->assertJson(fn (AssertableJson $json) => $json->where('action', 'link') + ->when($url)->where('url', $url) + ); + + return $this; + } + + public function assertReturnsReload(): static + { + $this->response->assertJson(fn (AssertableJson $json) => $json->where('action', 'reload') + ); + + return $this; + } + + public function assertReturnsRefresh(): static + { + $this->response->assertJson(fn (AssertableJson $json) => $json->where('action', 'refresh') + ); + + return $this; + } + + public function assertReturnsStep(string $step): static + { + $this->response->assertJson(fn (AssertableJson $json) => $json->where('action', 'step') + ); + + PHPUnit::assertEquals($step, Str::before($this->response->json('step'), ':')); + + return $this; + } +} diff --git a/src/Utils/Testing/DelegatesToResponse.php b/src/Utils/Testing/DelegatesToResponse.php new file mode 100644 index 000000000..8d1a6bbdd --- /dev/null +++ b/src/Utils/Testing/DelegatesToResponse.php @@ -0,0 +1,22 @@ +response->{$name}(...$arguments); + + return $this; + } +} diff --git a/src/Utils/Testing/EntityList/AssertableEntityList.php b/src/Utils/Testing/EntityList/AssertableEntityList.php new file mode 100644 index 000000000..e703cb02c --- /dev/null +++ b/src/Utils/Testing/EntityList/AssertableEntityList.php @@ -0,0 +1,42 @@ +listData()); + + return $this; + } + + public function assertListContains(array $attributes): self + { + PHPUnit::assertTrue( + collect($this->listData())->contains(fn ($item) => collect($attributes)->every(fn ($value, $key) => isset($item[$key]) && $item[$key] === $value) + ), + sprintf( + 'Failed asserting that data contains an item with attributes: %s', + json_encode($attributes) + ) + ); + + return $this; + } + + protected function listData(): array + { + return $this->response->inertiaProps('entityList.data'); + } +} diff --git a/src/Utils/Testing/EntityList/PendingEntityList.php b/src/Utils/Testing/EntityList/PendingEntityList.php new file mode 100644 index 000000000..f17039418 --- /dev/null +++ b/src/Utils/Testing/EntityList/PendingEntityList.php @@ -0,0 +1,127 @@ +entityKey = app(SharpEntityManager::class)->entityKeyFor($entityKey); + $this->entityList = app(SharpEntityManager::class)->entityFor($this->entityKey)->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->entityListQueryParams(), + ]) + ) + ); + } + + public function callEntityCommand( + string $commandKeyOrClassName, + array $data = [], + ?string $commandStep = null + ): AssertableCommand { + $this->setGlobalFilterUrlDefault(); + + $commandKey = class_exists($commandKeyOrClassName) + ? class_basename($commandKeyOrClassName) + : $commandKeyOrClassName; + + return new AssertableCommand( + $this + ->test + ->withHeader( + SharpBreadcrumb::CURRENT_PAGE_URL_HEADER, + $this->buildCurrentPageUrl( + $this->breadcrumbBuilder($this->entityKey) + ), + ) + ->postJson( + route( + 'code16.sharp.api.list.command.entity', + ['entityKey' => $this->entityKey, 'commandKey' => $commandKey] + ), + [ + 'data' => $data, + 'query' => $this->entityListQueryParams(), + 'command_step' => $commandStep, + ], + ) + ); + } + + public function callInstanceCommand( + int|string $instanceId, + string $commandKeyOrClassName, + array $data = [], + ?string $commandStep = null + ): AssertableCommand { + $this->setGlobalFilterUrlDefault(); + + $commandKey = class_exists($commandKeyOrClassName) + ? class_basename($commandKeyOrClassName) + : $commandKeyOrClassName; + + return new AssertableCommand( + $this + ->test + ->withHeader( + SharpBreadcrumb::CURRENT_PAGE_URL_HEADER, + $this->buildCurrentPageUrl( + $this->breadcrumbBuilder($this->entityKey, $instanceId) + ), + ) + ->postJson( + route( + 'code16.sharp.api.list.command.instance', + ['entityKey' => $this->entityKey, 'instanceId' => $instanceId, 'commandKey' => $commandKey] + ), + [ + 'data' => $data, + 'query' => $this->entityListQueryParams(), + 'command_step' => $commandStep, + ], + ) + ); + } + + protected function entityListQueryParams(): array + { + return $this->entityList + ->filterContainer() + ->getQueryParamsFromFilterValues($this->filterValues) + ->all(); + } +} 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/Http/SharpAssertionsHttpTest.php b/tests/Http/SharpAssertionsHttpTest.php new file mode 100644 index 000000000..ca9557374 --- /dev/null +++ b/tests/Http/SharpAssertionsHttpTest.php @@ -0,0 +1,72 @@ +use(SharpAssertions::class); + +beforeEach(function () { + login(); + sharp()->config()->declareEntity(PersonEntity::class); +}); + +it('gets an entity list', function () { + fakeListFor(PersonEntity::class, new class() extends PersonList + { + public function getListData(): array + { + return [ + ['id' => 1, 'name' => 'Marie Curie'], + ]; + } + }); + + $this->sharpList(PersonEntity::class) + ->get() + ->assertOk() + ->assertListCount(1) + ->assertListContains(['name' => 'Marie Curie']); +}); + +it('call an entity list entity command', function () { + fakeListFor('person', new class() extends PersonList + { + protected function getEntityCommands(): ?array + { + return [ + 'cmd' => new class() extends EntityCommand + { + public function label(): ?string + { + return 'entity'; + } + + public function buildFormFields(FieldsContainer $formFields): void + { + $formFields->addField(SharpFormTextField::make('action')); + } + + public function execute(array $data = []): array + { + return match ($data['action']) { + 'info' => $this->info('ok'), + 'link' => $this->link('https://example.org'), + }; + } + }, + ]; + } + }); + + $this->sharpList(PersonEntity::class) + ->callEntityCommand('cmd', ['action' => 'info']) + ->assertReturnsInfo('ok'); + + $this->sharpList(PersonEntity::class) + ->callEntityCommand('cmd', ['action' => 'link']) + ->assertReturnsLink('https://example.org'); +}); diff --git a/tests/Unit/Utils/Testing/SharpAssertionsTest.php b/tests/Unit/Utils/Testing/SharpAssertionsTest.php index 64b2fc166..d75e7ee5a 100644 --- a/tests/Unit/Utils/Testing/SharpAssertionsTest.php +++ b/tests/Unit/Utils/Testing/SharpAssertionsTest.php @@ -1,271 +1,108 @@ getSharpShow('leaves', 6); +beforeEach(function () { + sharp()->config()->declareEntity(PersonEntity::class); - $this->assertEquals( - route('code16.sharp.show.show', ['s-list/leaves', 'leaves', 6]), - $response->uri, - ); -}); - -it('allows to test getSharpForm for edit', function () { - $response = fakeResponse()->getSharpForm('leaves', 6); - - $this->assertEquals( - route('code16.sharp.form.edit', ['s-list/leaves', 'leaves', 6]), - $response->uri, - ); -}); - -it('allows to test getSharpForm for edit with a custom breadcrumb', function () { - $response = fakeResponse() - ->withSharpBreadcrumb( - fn ($builder) => $builder - ->appendEntityList('leaves') - ->appendShowPage('leaves', 6), - ) - ->getSharpForm('leaves', 6); - - $this->assertEquals( - route('code16.sharp.form.edit', ['s-list/leaves/s-show/leaves/6', 'leaves', 6]), - $response->uri, - ); -}); - -it('allows to test getSharpForm for single edit', function () { - $response = fakeResponse()->getSharpSingleForm('leaves'); - - $this->assertEquals( - route('code16.sharp.form.edit', ['s-list/leaves', 'leaves']), - $response->uri, - ); -}); - -it('allows to test getSharpForm for create', function () { - $response = fakeResponse()->getSharpForm('leaves'); - - $this->assertEquals( - route('code16.sharp.form.create', ['s-list/leaves', 'leaves']), - $response->uri, - ); -}); - -it('allows to test updateSharpForm for update', function () { - $response = fakeResponse()->updateSharpForm('leaves', 6, ['attr' => 'some_value']); - - $this->assertEquals( - route('code16.sharp.form.update', ['s-list/leaves', 'leaves', 6]), - $response->uri, - ); - - $this->assertEquals( - ['attr' => 'some_value'], - $response->postedData, - ); -}); - -it('allows to test updateSharpForm for single update', function () { - $response = fakeResponse() - ->updateSharpSingleForm('leaves', ['attr' => 'some_value']); - - $this->assertEquals( - route('code16.sharp.form.update', ['s-list/leaves', 'leaves']), - $response->uri, - ); - - $this->assertEquals( - ['attr' => 'some_value'], - $response->postedData, - ); -}); - -it('allows to test updateSharpForm for store', function () { - $response = fakeResponse()->storeSharpForm('leaves', ['attr' => 'some_value']); - - $this->assertEquals( - route('code16.sharp.form.store', ['s-list/leaves', 'leaves']), - $response->uri, - ); - - $this->assertEquals( - ['attr' => 'some_value'], - $response->postedData, - ); -}); - -it('allows to test deleteFromSharpList', function () { - $response = fakeResponse()->deleteFromSharpList('leaves', 6); - - $this->assertEquals( - route('code16.sharp.api.list.delete', ['leaves', 6]), - $response->uri, - ); -}); - -it('allows to test deleteSharpShow', function () { - $response = fakeResponse()->deleteFromSharpShow('leaves', 6); - - $this->assertEquals( - route('code16.sharp.show.delete', ['s-list/leaves', 'leaves', 6]), - $response->uri, - ); -}); - -it('allows to test callSharpInstanceCommandFromList', function () { - $response = fakeResponse() - ->callSharpInstanceCommandFromList('leaves', 6, 'command', ['attr' => 'some_value']); - - $this->assertEquals( - route('code16.sharp.api.list.command.instance', [ - 'entityKey' => 'leaves', - 'instanceId' => 6, - 'commandKey' => 'command', - ]), - $response->uri, - ); - - $this->assertEquals('some_value', $response->postedData->data->attr); -}); - -it('allows to test callSharpInstanceCommandFromShow', function () { - $response = fakeResponse() - ->callSharpInstanceCommandFromShow('leaves', 6, 'command', ['attr' => 'some_value']); - - $this->assertEquals( - route('code16.sharp.api.show.command.instance', [ - 'entityKey' => 'leaves', - 'instanceId' => 6, - 'commandKey' => 'command', - ]), - $response->uri, - ); - - $this->assertEquals('some_value', $response->postedData->data->attr); -}); - -it('allows to test callSharpInstanceCommandFromList with a wizard step', function () { - $response = fakeResponse() - ->callSharpInstanceCommandFromList('leaves', 6, 'command', ['attr' => 'some_value'], 'my-step:123'); - - $this->assertEquals('my-step:123', $response->postedData->command_step); -}); - -it('allows to define a current breadcrumb', function () { - $response = fakeResponse() - ->withSharpBreadcrumb( - fn ($builder) => $builder - ->appendEntityList('trees') - ->appendShowPage('trees', 2) - ->appendShowPage('leaves', 6), - ) - ->getSharpForm('leaves', 6); - - $this->assertEquals( - 'http://localhost/sharp/root/s-list/trees/s-show/trees/2/s-show/leaves/6/s-form/leaves/6', - $response->uri, - ); -}); - -it('allows to test getSharpForm for edit with a custom breadcrumb with legacy API', function () { - $response = fakeResponse() - ->withSharpCurrentBreadcrumb( - ['list', 'leaves'], - ['show', 'leaves', 6], + 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', + ]; + } + }, + ]; + } + }); +}); + +it('allows to test entity list', function () { + /** @var \Mockery\MockInterface|SharpAssertionsTestCase $testMock */ + $testMock = Mockery::mock(SharpAssertionsTestCase::class)->makePartial(); + + $testMock->shouldReceive('get') + ->once() + ->with(route('code16.sharp.list', [ + 'entityKey' => 'person', + 'filter_job' => 'physicist', + ])) + ->andReturn(new TestResponse(new Response())); + + $testMock->sharpList('person') + ->withFilter('job', 'physicist') + ->get() + ->assertOk(); +}); + +it('allows to test entity list instance command', function () { + /** @var \Mockery\MockInterface|SharpAssertionsTestCase $testMock */ + $testMock = Mockery::mock(SharpAssertionsTestCase::class)->makePartial(); + + $testMock->shouldReceive('postJson') + ->once() + ->with( + route('code16.sharp.api.list.command.instance', [ + 'entityKey' => 'person', + 'instanceId' => 1, + 'commandKey' => 'test', + ]), + [ + 'data' => ['foo' => 'bar'], + 'query' => ['filter_job' => 'physicist'], + 'command_step' => null, + ] ) - ->getSharpForm('leaves', 6); - - $this->assertEquals( - route('code16.sharp.form.edit', ['s-list/leaves/s-show/leaves/6', 'leaves', 6]), - $response->uri, - ); -}); - -it('allows to define a current breadcrumb with legacy API', function () { - $response = fakeResponse() - ->withSharpCurrentBreadcrumb( - ['list', 'trees'], - ['show', 'trees', 2], - ['show', 'leaves', 6], + ->andReturn(new TestResponse(new Response())); + + $testMock->sharpList('person') + ->withFilter('job', 'physicist') + ->callInstanceCommand(1, 'test', ['foo' => 'bar']) + ->assertOk(); +}); + +it('allows to test entity list entity command', function () { + /** @var \Mockery\MockInterface|SharpAssertionsTestCase $testMock */ + $testMock = Mockery::mock(SharpAssertionsTestCase::class)->makePartial(); + + $testMock->shouldReceive('postJson') + ->once() + ->with( + route('code16.sharp.api.list.command.entity', [ + 'entityKey' => 'person', + 'commandKey' => 'test', + ]), + [ + 'data' => ['foo' => 'bar'], + 'query' => ['filter_job' => 'physicist'], + 'command_step' => null, + ] ) - ->getSharpForm('leaves', 6); - - $this->assertEquals( - 'http://localhost/sharp/root/s-list/trees/s-show/trees/2/s-show/leaves/6/s-form/leaves/6', - $response->uri, - ); -}); - -it('allows to test getSharpForm for edit with global filter keys', function () { - fakeGlobalFilter('test-1'); - - $this->assertEquals( - route('code16.sharp.form.edit', [ - 'globalFilter' => 'root', - 'parentUri' => 's-list/leaves', - 'entityKey' => 'leaves', - 'instanceId' => 6, - ]), - fakeResponse() - ->getSharpForm('leaves', 6) - ->uri, - ); - - $this->assertEquals( - route('code16.sharp.form.edit', [ - 'globalFilter' => 'one', - 'parentUri' => 's-list/leaves', - 'entityKey' => 'leaves', - 'instanceId' => 6, - ]), - fakeResponse() - ->withSharpGlobalFilterValues('one') - ->getSharpForm('leaves', 6) - ->uri, - ); - - fakeGlobalFilter('test-2'); + ->andReturn(new TestResponse(new Response())); - $this->assertEquals( - route('code16.sharp.form.edit', [ - 'globalFilter' => 'one~two', - 'parentUri' => 's-list/leaves', - 'entityKey' => 'leaves', - 'instanceId' => 6, - ]), - fakeResponse() - ->withSharpGlobalFilterValues(['one', 'two']) - ->getSharpForm('leaves', 6) - ->uri, - ); + $testMock->sharpList('person') + ->withFilter('job', 'physicist') + ->callEntityCommand('test', ['foo' => 'bar']) + ->assertOk(); }); - -function fakeResponse() -{ - return new class('fake') extends Orchestra\Testbench\TestCase - { - use SharpAssertions; - - public $uri; - public $postedData; - - public function call($method, $uri, $parameters = [], $cookies = [], $files = [], $server = [], $content = null) - { - $this->uri = $uri; - - if ($parameters) { - $this->postedData = $parameters; - } elseif ($content) { - $this->postedData = json_decode($content); - } else { - $this->postedData = null; - } - - return $this; - } - }; -} diff --git a/tests/Unit/Utils/Testing/SharpAssertionsTestCase.php b/tests/Unit/Utils/Testing/SharpAssertionsTestCase.php new file mode 100644 index 000000000..3e392c2c4 --- /dev/null +++ b/tests/Unit/Utils/Testing/SharpAssertionsTestCase.php @@ -0,0 +1,11 @@ +getSharpShow('leaves', 6); + + $this->assertEquals( + route('code16.sharp.show.show', ['s-list/leaves', 'leaves', 6]), + $response->uri, + ); +}); + +it('allows to test getSharpForm for edit', function () { + $response = fakeResponse()->getSharpForm('leaves', 6); + + $this->assertEquals( + route('code16.sharp.form.edit', ['s-list/leaves', 'leaves', 6]), + $response->uri, + ); +}); + +it('allows to test getSharpForm for edit with a custom breadcrumb', function () { + $response = fakeResponse() + ->withSharpBreadcrumb( + fn ($builder) => $builder + ->appendEntityList('leaves') + ->appendShowPage('leaves', 6), + ) + ->getSharpForm('leaves', 6); + + $this->assertEquals( + route('code16.sharp.form.edit', ['s-list/leaves/s-show/leaves/6', 'leaves', 6]), + $response->uri, + ); +}); + +it('allows to test getSharpForm for single edit', function () { + $response = fakeResponse()->getSharpSingleForm('leaves'); + + $this->assertEquals( + route('code16.sharp.form.edit', ['s-list/leaves', 'leaves']), + $response->uri, + ); +}); + +it('allows to test getSharpForm for create', function () { + $response = fakeResponse()->getSharpForm('leaves'); + + $this->assertEquals( + route('code16.sharp.form.create', ['s-list/leaves', 'leaves']), + $response->uri, + ); +}); + +it('allows to test updateSharpForm for update', function () { + $response = fakeResponse()->updateSharpForm('leaves', 6, ['attr' => 'some_value']); + + $this->assertEquals( + route('code16.sharp.form.update', ['s-list/leaves', 'leaves', 6]), + $response->uri, + ); + + $this->assertEquals( + ['attr' => 'some_value'], + $response->postedData, + ); +}); + +it('allows to test updateSharpForm for single update', function () { + $response = fakeResponse() + ->updateSharpSingleForm('leaves', ['attr' => 'some_value']); + + $this->assertEquals( + route('code16.sharp.form.update', ['s-list/leaves', 'leaves']), + $response->uri, + ); + + $this->assertEquals( + ['attr' => 'some_value'], + $response->postedData, + ); +}); + +it('allows to test updateSharpForm for store', function () { + $response = fakeResponse()->storeSharpForm('leaves', ['attr' => 'some_value']); + + $this->assertEquals( + route('code16.sharp.form.store', ['s-list/leaves', 'leaves']), + $response->uri, + ); + + $this->assertEquals( + ['attr' => 'some_value'], + $response->postedData, + ); +}); + +it('allows to test deleteFromSharpList', function () { + $response = fakeResponse()->deleteFromSharpList('leaves', 6); + + $this->assertEquals( + route('code16.sharp.api.list.delete', ['leaves', 6]), + $response->uri, + ); +}); + +it('allows to test deleteSharpShow', function () { + $response = fakeResponse()->deleteFromSharpShow('leaves', 6); + + $this->assertEquals( + route('code16.sharp.show.delete', ['s-list/leaves', 'leaves', 6]), + $response->uri, + ); +}); + +it('allows to test callSharpInstanceCommandFromList', function () { + $response = fakeResponse() + ->callSharpInstanceCommandFromList('leaves', 6, 'command', ['attr' => 'some_value']); + + $this->assertEquals( + route('code16.sharp.api.list.command.instance', [ + 'entityKey' => 'leaves', + 'instanceId' => 6, + 'commandKey' => 'command', + ]), + $response->uri, + ); + + $this->assertEquals('some_value', $response->postedData->data->attr); +}); + +it('allows to test callSharpInstanceCommandFromShow', function () { + $response = fakeResponse() + ->callSharpInstanceCommandFromShow('leaves', 6, 'command', ['attr' => 'some_value']); + + $this->assertEquals( + route('code16.sharp.api.show.command.instance', [ + 'entityKey' => 'leaves', + 'instanceId' => 6, + 'commandKey' => 'command', + ]), + $response->uri, + ); + + $this->assertEquals('some_value', $response->postedData->data->attr); +}); + +it('allows to test callSharpInstanceCommandFromList with a wizard step', function () { + $response = fakeResponse() + ->callSharpInstanceCommandFromList('leaves', 6, 'command', ['attr' => 'some_value'], 'my-step:123'); + + $this->assertEquals('my-step:123', $response->postedData->command_step); +}); + +it('allows to define a current breadcrumb', function () { + $response = fakeResponse() + ->withSharpBreadcrumb( + fn ($builder) => $builder + ->appendEntityList('trees') + ->appendShowPage('trees', 2) + ->appendShowPage('leaves', 6), + ) + ->getSharpForm('leaves', 6); + + $this->assertEquals( + 'http://localhost/sharp/root/s-list/trees/s-show/trees/2/s-show/leaves/6/s-form/leaves/6', + $response->uri, + ); +}); + +it('allows to test getSharpForm for edit with a custom breadcrumb with legacy API', function () { + $response = fakeResponse() + ->withSharpCurrentBreadcrumb( + ['list', 'leaves'], + ['show', 'leaves', 6], + ) + ->getSharpForm('leaves', 6); + + $this->assertEquals( + route('code16.sharp.form.edit', ['s-list/leaves/s-show/leaves/6', 'leaves', 6]), + $response->uri, + ); +}); + +it('allows to define a current breadcrumb with legacy API', function () { + $response = fakeResponse() + ->withSharpCurrentBreadcrumb( + ['list', 'trees'], + ['show', 'trees', 2], + ['show', 'leaves', 6], + ) + ->getSharpForm('leaves', 6); + + $this->assertEquals( + 'http://localhost/sharp/root/s-list/trees/s-show/trees/2/s-show/leaves/6/s-form/leaves/6', + $response->uri, + ); +}); + +it('allows to test getSharpForm for edit with global filter keys', function () { + fakeGlobalFilter('test-1'); + + $this->assertEquals( + route('code16.sharp.form.edit', [ + 'globalFilter' => 'root', + 'parentUri' => 's-list/leaves', + 'entityKey' => 'leaves', + 'instanceId' => 6, + ]), + fakeResponse() + ->getSharpForm('leaves', 6) + ->uri, + ); + + $this->assertEquals( + route('code16.sharp.form.edit', [ + 'globalFilter' => 'one', + 'parentUri' => 's-list/leaves', + 'entityKey' => 'leaves', + 'instanceId' => 6, + ]), + fakeResponse() + ->withSharpGlobalFilterValues('one') + ->getSharpForm('leaves', 6) + ->uri, + ); + + fakeGlobalFilter('test-2'); + + $this->assertEquals( + route('code16.sharp.form.edit', [ + 'globalFilter' => 'one~two', + 'parentUri' => 's-list/leaves', + 'entityKey' => 'leaves', + 'instanceId' => 6, + ]), + fakeResponse() + ->withSharpGlobalFilterValues(['one', 'two']) + ->getSharpForm('leaves', 6) + ->uri, + ); +}); + +function fakeResponse() +{ + return new class('fake') extends Orchestra\Testbench\TestCase + { + use SharpAssertions; + + public $uri; + public $postedData; + + public function call($method, $uri, $parameters = [], $cookies = [], $files = [], $server = [], $content = null) + { + $this->uri = $uri; + + if ($parameters) { + $this->postedData = $parameters; + } elseif ($content) { + $this->postedData = json_decode($content); + } else { + $this->postedData = null; + } + + return $this; + } + }; +}