From 8299b8656648e02399994b8e1ba2cb7e900b72e7 Mon Sep 17 00:00:00 2001 From: Alan Ostaszewski Date: Mon, 19 May 2025 23:54:55 +0200 Subject: [PATCH 1/4] test: add test for conditional visibility and dehydration of fields in a section component with state path --- tests/src/Forms/StateTest.php | 46 +++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/tests/src/Forms/StateTest.php b/tests/src/Forms/StateTest.php index f7acaa37a8..eb8df281f4 100644 --- a/tests/src/Forms/StateTest.php +++ b/tests/src/Forms/StateTest.php @@ -7,6 +7,9 @@ use Filament\Forms\Get; use Filament\Tests\Forms\Fixtures\Livewire; use Filament\Tests\TestCase; use Illuminate\Support\Str; +use Filament\Forms\Components\Section; +use Filament\Forms\Components\Radio; +use Filament\Forms\Components\TextInput; uses(TestCase::class); @@ -706,3 +709,46 @@ test('parent sibling state can be retrieved absolutely from another component', expect($placeholder) ->getContent()->toBe($state); }); + +test( + 'conditionally hidden and non-dehydrated field within a section (with state path) is incorrectly dehydrated when hidden', + function () { + $container = ComponentContainer::make(Livewire::make()) + ->components([ + Section::make("User Information") + ->statePath('data') + ->schema([ + Radio::make('show_input') + ->label('Control Input Visibility') + ->options([ + 'show' => 'Show', + 'hide' => 'Hide', + ]) + ->live(), + + TextInput::make('name') + ->label('Conditional Name') + ->hidden(fn (Get $get): bool => $get('show_input') === 'hide' || $get('show_input') === null) + ->dehydrated(fn (Get $get): bool => $get('show_input') === 'show'), + ]), + ]) + ->fill([ + 'data' => [ + 'show_input' => 'hide', + 'name' => 'lorem ipsum', + ] + ]); + + $dehydratedState = $container->dehydrateState(); + + // Assert: Expect 'name' field NOT to be present in dehydrated state when 'show_input' is 'hide' + // This assertion is designed to FAIL due to the bug, thus documenting it. + expect($dehydratedState) + ->toBe([ + 'data' => [ + 'show_input' => 'hide', + // 'name' field with 'lorem ipsum' should NOT be here if the bug was fixed. + ], + ]); + } +); \ No newline at end of file From 316737763274f1db4932304b5a952fdbe4d715ec Mon Sep 17 00:00:00 2001 From: Alan Ostaszewski Date: Mon, 19 May 2025 23:58:41 +0200 Subject: [PATCH 2/4] chore: code style --- tests/src/Forms/StateTest.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/src/Forms/StateTest.php b/tests/src/Forms/StateTest.php index eb8df281f4..51a9b64bcc 100644 --- a/tests/src/Forms/StateTest.php +++ b/tests/src/Forms/StateTest.php @@ -3,13 +3,13 @@ use Filament\Forms\ComponentContainer; use Filament\Forms\Components\Component; use Filament\Forms\Components\Placeholder; +use Filament\Forms\Components\Radio; +use Filament\Forms\Components\Section; +use Filament\Forms\Components\TextInput; use Filament\Forms\Get; use Filament\Tests\Forms\Fixtures\Livewire; use Filament\Tests\TestCase; use Illuminate\Support\Str; -use Filament\Forms\Components\Section; -use Filament\Forms\Components\Radio; -use Filament\Forms\Components\TextInput; uses(TestCase::class); @@ -715,7 +715,7 @@ test( function () { $container = ComponentContainer::make(Livewire::make()) ->components([ - Section::make("User Information") + Section::make('User Information') ->statePath('data') ->schema([ Radio::make('show_input') @@ -736,7 +736,7 @@ test( 'data' => [ 'show_input' => 'hide', 'name' => 'lorem ipsum', - ] + ], ]); $dehydratedState = $container->dehydrateState(); @@ -751,4 +751,4 @@ test( ], ]); } -); \ No newline at end of file +); From 8e2432edb9476319c0870e06d33cd3f30f60c768 Mon Sep 17 00:00:00 2001 From: Dan Harrin Date: Tue, 20 May 2025 11:27:42 +0100 Subject: [PATCH 3/4] fix issue --- packages/forms/src/Components/Concerns/HasState.php | 12 ++++++------ packages/forms/src/Concerns/HasState.php | 8 -------- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/packages/forms/src/Components/Concerns/HasState.php b/packages/forms/src/Components/Concerns/HasState.php index f33f1d57d6..37d8bba409 100644 --- a/packages/forms/src/Components/Concerns/HasState.php +++ b/packages/forms/src/Components/Concerns/HasState.php @@ -186,16 +186,12 @@ trait HasState return; } - if ($this->getStatePath(isAbsolute: false)) { + if ($this->hasStatePath()) { foreach ($this->getStateToDehydrate() as $key => $value) { Arr::set($state, $key, $value); } } - if ($this->isHiddenAndNotDehydrated()) { - return; - } - foreach ($this->getChildComponentContainers(withHidden: true) as $container) { $container->dehydrateState($state, $isDehydrated); } @@ -438,7 +434,11 @@ trait HasState public function isDehydrated(): bool { - return (bool) $this->evaluate($this->isDehydrated); + if (! $this->evaluate($this->isDehydrated)) { + return false; + } + + return ! $this->isHiddenAndNotDehydrated(); } public function isDehydratedWhenHidden(): bool diff --git a/packages/forms/src/Concerns/HasState.php b/packages/forms/src/Concerns/HasState.php index d6c65009f9..acf82a1255 100644 --- a/packages/forms/src/Concerns/HasState.php +++ b/packages/forms/src/Concerns/HasState.php @@ -72,10 +72,6 @@ trait HasState public function dehydrateState(array &$state = [], bool $isDehydrated = true): array { foreach ($this->getComponents(withHidden: true) as $component) { - if ($component->isHiddenAndNotDehydrated()) { - continue; - } - $component->dehydrateState($state, $isDehydrated); } @@ -89,10 +85,6 @@ trait HasState public function mutateDehydratedState(array &$state = []): array { foreach ($this->getComponents(withHidden: true) as $component) { - if ($component->isHiddenAndNotDehydrated()) { - continue; - } - if (! $component->isDehydrated()) { continue; } From 3121b74041187df7873bbb7c730d2e2d0dbe2384 Mon Sep 17 00:00:00 2001 From: Dan Harrin Date: Tue, 20 May 2025 11:28:42 +0100 Subject: [PATCH 4/4] simplify test --- tests/src/Forms/StateTest.php | 66 ++++++++++++----------------------- 1 file changed, 23 insertions(+), 43 deletions(-) diff --git a/tests/src/Forms/StateTest.php b/tests/src/Forms/StateTest.php index 51a9b64bcc..64a28815d3 100644 --- a/tests/src/Forms/StateTest.php +++ b/tests/src/Forms/StateTest.php @@ -511,6 +511,29 @@ test('hidden components are excluded from state dehydration except if they are m ->dehydrateState()->not()->toBe([]); }); +test('hidden components are excluded from state dehydration even if their parent component has a state path', function () { + $container = ComponentContainer::make(Livewire::make()) + ->statePath('data') + ->components([ + (new Component) + ->statePath('nested') + ->schema([ + (new Component) + ->statePath(Str::random()) + ->default(Str::random()) + ->hidden(), + ]), + ]) + ->fill(); + + expect($container) + ->dehydrateState()->toBe([ + 'data' => [ + 'nested' => [], + ], + ]); +}); + test('disabled components are excluded from state dehydration', function () { $container = ComponentContainer::make(Livewire::make()) ->statePath('data') @@ -709,46 +732,3 @@ test('parent sibling state can be retrieved absolutely from another component', expect($placeholder) ->getContent()->toBe($state); }); - -test( - 'conditionally hidden and non-dehydrated field within a section (with state path) is incorrectly dehydrated when hidden', - function () { - $container = ComponentContainer::make(Livewire::make()) - ->components([ - Section::make('User Information') - ->statePath('data') - ->schema([ - Radio::make('show_input') - ->label('Control Input Visibility') - ->options([ - 'show' => 'Show', - 'hide' => 'Hide', - ]) - ->live(), - - TextInput::make('name') - ->label('Conditional Name') - ->hidden(fn (Get $get): bool => $get('show_input') === 'hide' || $get('show_input') === null) - ->dehydrated(fn (Get $get): bool => $get('show_input') === 'show'), - ]), - ]) - ->fill([ - 'data' => [ - 'show_input' => 'hide', - 'name' => 'lorem ipsum', - ], - ]); - - $dehydratedState = $container->dehydrateState(); - - // Assert: Expect 'name' field NOT to be present in dehydrated state when 'show_input' is 'hide' - // This assertion is designed to FAIL due to the bug, thus documenting it. - expect($dehydratedState) - ->toBe([ - 'data' => [ - 'show_input' => 'hide', - // 'name' field with 'lorem ipsum' should NOT be here if the bug was fixed. - ], - ]); - } -);