How to test elements in a repeater? #6070
-
I am trying to make sure the first element I feed into my form address repeater is marked primary. When I run the following test $page = Livewire::test(Create::class)
->assertFormExists('form')
->assertFormSet([
'business_addresses' => [[
'is_primary_address' => true,
]]
]); When I set that data in my Failed asserting that two arrays are equal.
--- Expected
+++ Actual
@@ @@
Array (
- 0 => Array (...)
+ 'f5204905-4fa5-4842-bd77-2c4874917587' => Array (...)
) because of the UUID indexes that are added. Is there a built in way to assert items in a repeater? |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 11 replies
-
Good question. I don't have an answer. What can we add to the core to help this? Maybe submit a PR |
Beta Was this translation helpful? Give feedback.
-
We are using this overridden repeater component for now, which works for unit and dusk testing. <?php
namespace App\Filament\CustomComponents;
use Closure;
use Filament\Forms\Components\Field;
use Filament\Forms\Components\Repeater;
use function Filament\Forms\array_move_after;
use function Filament\Forms\array_move_before;
class SequencedRepeater extends Repeater
{
protected const REPEATER_SET_KEY = 'repeater-set-';
public function defaultItems(int|Closure $count): static
{
$this->default(function (SequencedRepeater $component) use ($count): array {
$items = [];
$count = $component->evaluate($count);
if (!$count) {
return $items;
}
foreach (range(1, $count) as $index) {
$items[SequencedRepeater::REPEATER_SET_KEY.($index - 1)] = [];
}
return $items;
});
return $this;
}
protected function setUp(): void
{
Field::setUp();
$this->defaultItems(1);
$this->afterStateHydrated(function (SequencedRepeater $component, ?array $state): void {
$items = [];
foreach ($state ?? [] as $index => $itemData) {
$items[SequencedRepeater::REPEATER_SET_KEY.$index] = $itemData;
}
$component->state($items);
});
$this->registerListeners([
'repeater::createItem' => [
function (SequencedRepeater $component, string $statePath): void {
if ($statePath !== $component->getStatePath()) {
return;
}
$livewire = $component->getLivewire();
$repeaterState = data_get($livewire, $statePath, []);
$repeaterKeys = array_keys($repeaterState);
$repeaterIndexes = array_map(fn($repKey) => (int) str_replace(SequencedRepeater::REPEATER_SET_KEY, '', $repKey), $repeaterKeys);
$newUuid = SequencedRepeater::REPEATER_SET_KEY.(max($repeaterIndexes ?: [-1]) + 1);
data_set($livewire, "{$statePath}.{$newUuid}", []);
$component->getChildComponentContainers()[$newUuid]->fill();
$component->collapsed(false, shouldMakeComponentCollapsible: false);
},
],
'repeater::deleteItem' => [
function (SequencedRepeater $component, string $statePath, string $uuidToDelete): void {
if ($statePath !== $component->getStatePath()) {
return;
}
$items = $component->getState();
unset($items[$uuidToDelete]);
$livewire = $component->getLivewire();
data_set($livewire, $statePath, $items);
},
],
'repeater::cloneItem' => [
function (SequencedRepeater $component, string $statePath, string $uuidToDuplicate): void {
if ($statePath !== $component->getStatePath()) {
return;
}
$livewire = $component->getLivewire();
$repeaterState = data_get($livewire, $statePath, []);
$repeaterKeys = array_keys($repeaterState);
$repeaterIndexes = array_map(fn($repKey) => (int) str_replace(SequencedRepeater::REPEATER_SET_KEY, '', $repKey), $repeaterKeys);
$newUuid = SequencedRepeater::REPEATER_SET_KEY.(max($repeaterIndexes ?: [-1]) + 1);
data_set(
$livewire,
"{$statePath}.{$newUuid}",
data_get($livewire, "{$statePath}.{$uuidToDuplicate}"),
);
$component->collapsed(false, shouldMakeComponentCollapsible: false);
},
],
'repeater::moveItemDown' => [
function (SequencedRepeater $component, string $statePath, string $uuidToMoveDown): void {
if ($component->isItemMovementDisabled()) {
return;
}
if ($statePath !== $component->getStatePath()) {
return;
}
$items = array_move_after($component->getState(), $uuidToMoveDown);
$livewire = $component->getLivewire();
data_set($livewire, $statePath, $items);
},
],
'repeater::moveItemUp' => [
function (SequencedRepeater $component, string $statePath, string $uuidToMoveUp): void {
if ($component->isItemMovementDisabled()) {
return;
}
if ($statePath !== $component->getStatePath()) {
return;
}
$items = array_move_before($component->getState(), $uuidToMoveUp);
$livewire = $component->getLivewire();
data_set($livewire, $statePath, $items);
},
],
'repeater::moveItems' => [
function (SequencedRepeater $component, string $statePath, array $uuids): void {
if ($component->isItemMovementDisabled()) {
return;
}
if ($statePath !== $component->getStatePath()) {
return;
}
$items = array_merge(array_flip($uuids), $component->getState());
$livewire = $component->getLivewire();
data_set($livewire, $statePath, $items);
},
],
]);
$this->createItemButtonLabel(static function (SequencedRepeater $component) {
return __('forms::components.repeater.buttons.create_item.label', [
'label' => lcfirst($component->getLabel()),
]);
});
$this->mutateDehydratedStateUsing(static function (?array $state): array {
return array_values($state ?? []);
});
}
} |
Beta Was this translation helpful? Give feedback.
-
For those bumping into this from Google, there looks to now be a Fake command that helps with this: https://filamentphp.com/docs/3.x/forms/fields/repeater#testing-repeaters |
Beta Was this translation helpful? Give feedback.
For those bumping into this from Google, there looks to now be a Fake command that helps with this: https://filamentphp.com/docs/3.x/forms/fields/repeater#testing-repeaters