From 587e0be28fa7a6ab59bcab7aca979c18e6c67bda Mon Sep 17 00:00:00 2001 From: luanfreitasdev Date: Thu, 26 Sep 2024 14:40:47 -0300 Subject: [PATCH 1/3] wip --- src/Providers/PowerGridServiceProvider.php | 9 ++- src/Testing/TestActions.php | 75 ++++++++++++++++++++++ 2 files changed, 81 insertions(+), 3 deletions(-) create mode 100644 src/Testing/TestActions.php diff --git a/src/Providers/PowerGridServiceProvider.php b/src/Providers/PowerGridServiceProvider.php index c03e6c3c..0888f07d 100644 --- a/src/Providers/PowerGridServiceProvider.php +++ b/src/Providers/PowerGridServiceProvider.php @@ -6,15 +6,16 @@ use Illuminate\Support\Facades\{Blade, Event}; use Illuminate\Support\{ServiceProvider}; use Livewire\Features\SupportLegacyModels\{EloquentCollectionSynth, EloquentModelSynth}; +use Livewire\Features\SupportTesting\Testable; use Livewire\Livewire; use PowerComponents\LivewirePowerGrid\Commands\{CreateCommand, PublishCommand, UpdateCommand}; use PowerComponents\LivewirePowerGrid\Components\Filters\FilterManager; use PowerComponents\LivewirePowerGrid\Components\Rules\RuleManager; use PowerComponents\LivewirePowerGrid\Support\PowerGridTableCache; -use PowerComponents\LivewirePowerGrid\{ - Livewire\LazyChild, +use PowerComponents\LivewirePowerGrid\{Livewire\LazyChild, Livewire\PerformanceCard, - PowerGridManager}; + PowerGridManager, + Testing\TestActions}; /** @codeCoverageIgnore */ class PowerGridServiceProvider extends ServiceProvider @@ -35,6 +36,8 @@ public function boot(): void Livewire::propertySynthesizer(EloquentModelSynth::class); Livewire::propertySynthesizer(EloquentCollectionSynth::class); + + Testable::mixin(new TestActions()); } public function register(): void diff --git a/src/Testing/TestActions.php b/src/Testing/TestActions.php new file mode 100644 index 00000000..1cec1895 --- /dev/null +++ b/src/Testing/TestActions.php @@ -0,0 +1,75 @@ +flatten(1) + ->contains(fn($dishAction) => $dishAction['action'] === $action); + + Assert::assertTrue($actionFound, "Failed asserting that the action '$action' exists in the table."); + + return $this; + }; + } + + public function assertActionHasIcon(): Closure + { + return function (string $action, string $icon, ?string $iconClass = null): static { + $actionFound = collect(DataSourceBase::$actionsHtml) + ->flatten(1) + ->first(fn($dishAction) => $dishAction['action'] === $action && $dishAction['icon'] === $icon); + + Assert::assertNotNull($actionFound, "Failed asserting that the action '$action' has the icon '$icon'."); + + if ($iconClass !== null) { + $iconClassFound = isset($actionFound['iconAttributes']['class']) && str_contains($actionFound['iconAttributes']['class'], $iconClass); + Assert::assertTrue($iconClassFound, "Failed asserting that the icon of action '$action' contains the class '$iconClass'."); + } + + return $this; + }; + } + + public function assertActionContainsAttribute(): Closure + { + return function (string $action, string $attribute, string $expected, array $expectedParams = []): static { + $attributeFound = collect(DataSourceBase::$actionsHtml) + ->flatten(1) + ->first(function ($dishAction) use ($action, $attribute, $expected, $expectedParams) { + if ($dishAction['action'] === $action && isset($dishAction['attributes'][$attribute])) { + $attributeValue = $dishAction['attributes'][$attribute]; + + Js::from(); + if (str_contains($attributeValue, 'JSON.parse')) { + preg_match("/JSON\.parse\('(.*)'\)/", $attributeValue, $matches); + $jsonEscaped = $matches[1] ?? null; + + if ($jsonEscaped) { + $jsonStringClean = json_decode('"' . $jsonEscaped . '"', true); + $data = json_decode($jsonStringClean, true); + + return $data == $expectedParams; + } + } + + return str_contains($attributeValue, $expected); + } + return false; + }); + + Assert::assertNotNull($attributeFound, "Failed asserting that the '$attribute' of action '$action' contains the expected parameters."); + + return $this; + }; + } +} From fdca5e6b2433819754dc0f0efeb46198746ec921 Mon Sep 17 00:00:00 2001 From: luanfreitasdev Date: Thu, 26 Sep 2024 16:32:33 -0300 Subject: [PATCH 2/3] Add Testing class for asserts --- src/Testing/TestActions.php | 12 +- tests/Feature/Testing/TestActionsTest.php | 132 ++++++++++++++++++++++ 2 files changed, 138 insertions(+), 6 deletions(-) create mode 100644 tests/Feature/Testing/TestActionsTest.php diff --git a/src/Testing/TestActions.php b/src/Testing/TestActions.php index 1cec1895..3cd156c2 100644 --- a/src/Testing/TestActions.php +++ b/src/Testing/TestActions.php @@ -3,7 +3,7 @@ namespace PowerComponents\LivewirePowerGrid\Testing; use Closure; -use Illuminate\Support\Js; + use PHPUnit\Framework\Assert; use PowerComponents\LivewirePowerGrid\DataSource\Processors\DataSourceBase; @@ -14,7 +14,7 @@ public function assertHasAction(): Closure return function (string $action): static { $actionFound = collect(DataSourceBase::$actionsHtml) ->flatten(1) - ->contains(fn($dishAction) => $dishAction['action'] === $action); + ->contains(fn (array $dishAction): bool => $dishAction['action'] === $action); Assert::assertTrue($actionFound, "Failed asserting that the action '$action' exists in the table."); @@ -27,7 +27,7 @@ public function assertActionHasIcon(): Closure return function (string $action, string $icon, ?string $iconClass = null): static { $actionFound = collect(DataSourceBase::$actionsHtml) ->flatten(1) - ->first(fn($dishAction) => $dishAction['action'] === $action && $dishAction['icon'] === $icon); + ->first(fn (array $dishAction) => $dishAction['action'] === $action && $dishAction['icon'] === $icon); Assert::assertNotNull($actionFound, "Failed asserting that the action '$action' has the icon '$icon'."); @@ -45,18 +45,17 @@ public function assertActionContainsAttribute(): Closure return function (string $action, string $attribute, string $expected, array $expectedParams = []): static { $attributeFound = collect(DataSourceBase::$actionsHtml) ->flatten(1) - ->first(function ($dishAction) use ($action, $attribute, $expected, $expectedParams) { + ->first(function (array $dishAction) use ($action, $attribute, $expected, $expectedParams) { if ($dishAction['action'] === $action && isset($dishAction['attributes'][$attribute])) { $attributeValue = $dishAction['attributes'][$attribute]; - Js::from(); if (str_contains($attributeValue, 'JSON.parse')) { preg_match("/JSON\.parse\('(.*)'\)/", $attributeValue, $matches); $jsonEscaped = $matches[1] ?? null; if ($jsonEscaped) { $jsonStringClean = json_decode('"' . $jsonEscaped . '"', true); - $data = json_decode($jsonStringClean, true); + $data = json_decode($jsonStringClean, true); return $data == $expectedParams; } @@ -64,6 +63,7 @@ public function assertActionContainsAttribute(): Closure return str_contains($attributeValue, $expected); } + return false; }); diff --git a/tests/Feature/Testing/TestActionsTest.php b/tests/Feature/Testing/TestActionsTest.php new file mode 100644 index 00000000..de42b3d6 --- /dev/null +++ b/tests/Feature/Testing/TestActionsTest.php @@ -0,0 +1,132 @@ +showToggleColumns() + ->showSearchInput(), + + PowerGrid::footer() + ->showPerPage() + ->showRecordCount(), + ]; + } + + public function datasource(): Collection + { + return collect([ + [ + 'id' => 29, + 'name' => 'Luan', + 'balance' => 241.86, + 'is_online' => true, + 'created_at' => '2023-01-01 00:00:00', + ], + [ + 'id' => 57, + 'name' => 'Daniel', + 'balance' => 166.51, + 'is_online' => true, + 'created_at' => '2023-02-02 00:00:00', + ], + [ + 'id' => 93, + 'name' => 'Claudio', + 'balance' => 219.01, + 'is_online' => false, + 'created_at' => '2023-03-03 00:00:00', + ], + [ + 'id' => 104, + 'name' => 'Vitor', + 'balance' => 44.28, + 'is_online' => true, + 'created_at' => '2023-04-04 00:00:00', + ], + ]); + } + + public function fields(): PowerGridFields + { + return PowerGrid::fields() + ->add('id') + ->add('name') + ->add('balance', fn ($item) => Number::currency($item->balance, in: 'BRL', locale: 'pt-BR')) + ->add('is_online', fn ($item) => $item->is_online ? '✅' : '❌') + ->add('created_at', fn ($item) => Carbon::parse($item->created_at)) + ->add('created_at_formatted', fn ($item) => Carbon::parse($item->created_at)->format('d/m/Y')); + } + + public function columns(): array + { + return [ + Column::make('Index', 'id')->index(), + + Column::make('ID', 'id'), + + Column::add() + ->title('Name') + ->field('name') + ->searchable() + ->sortable(), + + Column::add() + ->title('Balance') + ->field('balance') + ->sortable(), + + Column::add() + ->title('Online') + ->field('is_online'), + + Column::add() + ->title('Created At') + ->field('created_at_formatted'), + + Column::action('Action'), + ]; + } + + public function actions($row): array + { + return [ + Button::add('view') + ->icon('default-eye', [ + 'class' => '!text-green-500', + ]) + ->slot('View') + ->class('text-slate-500 flex gap-2 hover:text-slate-700 hover:bg-slate-100 font-bold p-1 px-2 rounded') + ->dispatch('clickToEdit', ['dishId' => $row?->id, 'dishName' => $row?->name]), + ]; + } + + public function setTestThemeClass(string $themeClass): void + { + config(['livewire-powergrid.theme' => $themeClass]); + } +}; + +it('testings', function (string $component, object $params) { + livewire($component) + ->call('setTestThemeClass', $params->theme) + ->assertHasAction('view') + ->assertActionContainsAttribute('view', 'class', 'flex gap-2 hover:text-slate-700') + ->assertActionContainsAttribute('view', 'wire:click', 'clickToEdit', ['dishId' => 29, 'dishName' => 'Luan']) + ->assertActionHasIcon('view', 'default-eye', '!text-green-500') + ->assertOk(); +})->with([ + 'tailwind' => [$component::class, (object) ['theme' => Tailwind::class]], + 'bootstrap' => [$component::class, (object) ['theme' => Bootstrap5::class]], +]); From cb88010a1951fb59565b0c612a9b46acd5d26690 Mon Sep 17 00:00:00 2001 From: luanfreitasdev Date: Thu, 26 Sep 2024 16:40:25 -0300 Subject: [PATCH 3/3] phpstan fixes --- src/Testing/TestActions.php | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/Testing/TestActions.php b/src/Testing/TestActions.php index 3cd156c2..da18022e 100644 --- a/src/Testing/TestActions.php +++ b/src/Testing/TestActions.php @@ -25,9 +25,13 @@ public function assertHasAction(): Closure public function assertActionHasIcon(): Closure { return function (string $action, string $icon, ?string $iconClass = null): static { + /** @var array $actionFound */ $actionFound = collect(DataSourceBase::$actionsHtml) ->flatten(1) - ->first(fn (array $dishAction) => $dishAction['action'] === $action && $dishAction['icon'] === $icon); + ->first(function ($dishAction) use ($action, $icon) { + /** @var array $dishAction */ + return $dishAction['action'] === $action && $dishAction['icon'] === $icon; + }); Assert::assertNotNull($actionFound, "Failed asserting that the action '$action' has the icon '$icon'."); @@ -45,7 +49,8 @@ public function assertActionContainsAttribute(): Closure return function (string $action, string $attribute, string $expected, array $expectedParams = []): static { $attributeFound = collect(DataSourceBase::$actionsHtml) ->flatten(1) - ->first(function (array $dishAction) use ($action, $attribute, $expected, $expectedParams) { + ->first(function ($dishAction) use ($action, $attribute, $expected, $expectedParams) { + /** @var array $dishAction */ if ($dishAction['action'] === $action && isset($dishAction['attributes'][$attribute])) { $attributeValue = $dishAction['attributes'][$attribute]; @@ -54,7 +59,7 @@ public function assertActionContainsAttribute(): Closure $jsonEscaped = $matches[1] ?? null; if ($jsonEscaped) { - $jsonStringClean = json_decode('"' . $jsonEscaped . '"', true); + $jsonStringClean = strval(json_decode('"' . $jsonEscaped . '"', true)); $data = json_decode($jsonStringClean, true); return $data == $expectedParams;