diff --git a/docs/guide/testing.md b/docs/guide/testing.md index afe8c7da0..37173922e 100644 --- a/docs/guide/testing.md +++ b/docs/guide/testing.md @@ -279,3 +279,13 @@ $this->sharpDashboard(MyDashboard::class) ->post() ->assertOk(); ``` + +## Global filters + +If your app contains global filters, you should be able to test normally, but it will be set to its default value. If you need, you can set a specific value using `withGlobalFilter()`: + +```php +$this->withSharpGlobalFilter(CompanyFilter::class, 'apple') + ->sharpList(Post::class) + //... +``` diff --git a/src/Filters/GlobalFilters/GlobalFilters.php b/src/Filters/GlobalFilters/GlobalFilters.php index ecc3a01a1..7954681ee 100644 --- a/src/Filters/GlobalFilters/GlobalFilters.php +++ b/src/Filters/GlobalFilters/GlobalFilters.php @@ -53,9 +53,14 @@ public function toArray(): array } public function isDeclared(string $key): bool + { + return $this->getDeclaredFilter($key) !== null; + } + + public function getDeclaredFilter(string $key): ?GlobalRequiredFilter { return collect(sharp()->config()->get('global_filters')) - ->contains(function (GlobalRequiredFilter $filter) use ($key) { + ->first(function (GlobalRequiredFilter $filter) use ($key) { $filter->buildFilterConfig(); if (class_exists($key)) { diff --git a/src/Utils/Testing/Commands/PendingCommand.php b/src/Utils/Testing/Commands/PendingCommand.php index dc713078b..faff399be 100644 --- a/src/Utils/Testing/Commands/PendingCommand.php +++ b/src/Utils/Testing/Commands/PendingCommand.php @@ -21,8 +21,6 @@ public function __construct( public function getForm(): AssertableCommandForm { - $this->setGlobalFilterUrlDefault(); - return new AssertableCommandForm( post: $this->post, getForm: $this->getForm, @@ -33,8 +31,6 @@ public function getForm(): AssertableCommandForm public function post(): AssertableCommand { - $this->setGlobalFilterUrlDefault(); - return new AssertableCommand( postCommand: $this->post, getForm: $this->getForm, diff --git a/src/Utils/Testing/Dashboard/PendingDashboard.php b/src/Utils/Testing/Dashboard/PendingDashboard.php index aced2f3d3..866f4de73 100644 --- a/src/Utils/Testing/Dashboard/PendingDashboard.php +++ b/src/Utils/Testing/Dashboard/PendingDashboard.php @@ -10,6 +10,7 @@ use Code16\Sharp\Utils\Testing\Commands\FormatsDataForCommand; use Code16\Sharp\Utils\Testing\Commands\PendingCommand; use Code16\Sharp\Utils\Testing\IsPendingComponent; +use Code16\Sharp\Utils\Testing\SharpAssertions; use Code16\Sharp\Utils\Testing\Show\PendingShow; use Illuminate\Foundation\Testing\TestCase; @@ -23,7 +24,7 @@ class PendingDashboard protected array $filterValues = []; public function __construct( - /** @var TestCase $test */ + /** @var TestCase&SharpAssertions $test */ protected object $test, string $entityKey, public ?PendingShow $parent = null, @@ -42,8 +43,6 @@ public function withFilter(string $filterKey, mixed $value): static public function get(): AssertableDashboard { - $this->setGlobalFilterUrlDefault(); - return new AssertableDashboard( $this->parent instanceof PendingShow ? $this->test @@ -69,8 +68,6 @@ public function get(): AssertableDashboard public function dashboardCommand(string $commandKeyOrClassName): PendingCommand { - $this->setGlobalFilterUrlDefault(); - $commandKey = class_exists($commandKeyOrClassName) ? class_basename($commandKeyOrClassName) : $commandKeyOrClassName; diff --git a/src/Utils/Testing/EntityList/PendingEntityList.php b/src/Utils/Testing/EntityList/PendingEntityList.php index 43167bd75..b5d075fb5 100644 --- a/src/Utils/Testing/EntityList/PendingEntityList.php +++ b/src/Utils/Testing/EntityList/PendingEntityList.php @@ -11,6 +11,7 @@ use Code16\Sharp\Utils\Testing\Commands\PendingCommand; use Code16\Sharp\Utils\Testing\Form\PendingForm; use Code16\Sharp\Utils\Testing\IsPendingComponent; +use Code16\Sharp\Utils\Testing\SharpAssertions; use Code16\Sharp\Utils\Testing\Show\PendingShow; use Illuminate\Foundation\Testing\TestCase; use PHPUnit\Framework\Assert as PHPUnit; @@ -25,7 +26,7 @@ class PendingEntityList protected array $filterValues = []; public function __construct( - /** @var TestCase $test */ + /** @var TestCase&SharpAssertions $test */ protected object $test, string $entityKey, public ?PendingShow $parent = null, @@ -50,16 +51,17 @@ public function sharpForm(string $entityClassNameOrKey, string|int $instanceId): public function withFilter(string $filterKey, mixed $value): static { - $key = $this->entityList->filterContainer()->findFilterHandler($filterKey)->getKey(); - $this->filterValues[$key] = $value; + $filter = $this->entityList->filterContainer()->findFilterHandler($filterKey); + + PHPUnit::assertNotNull($filter, sprintf('Unknown entity list filter [%s]', $filterKey)); + + $this->filterValues[$filter->getKey()] = $value; return $this; } public function get(): AssertableEntityList { - $this->setGlobalFilterUrlDefault(); - return new AssertableEntityList( $this->parent instanceof PendingShow ? $this->test @@ -85,8 +87,6 @@ public function get(): AssertableEntityList public function entityCommand(string $commandKeyOrClassName): PendingCommand { - $this->setGlobalFilterUrlDefault(); - $commandKey = class_exists($commandKeyOrClassName) ? class_basename($commandKeyOrClassName) : $commandKeyOrClassName; @@ -134,8 +134,6 @@ public function entityCommand(string $commandKeyOrClassName): PendingCommand public function instanceCommand(string $commandKeyOrClassName, int|string $instanceId): PendingCommand { - $this->setGlobalFilterUrlDefault(); - $commandKey = class_exists($commandKeyOrClassName) ? class_basename($commandKeyOrClassName) : $commandKeyOrClassName; diff --git a/src/Utils/Testing/Form/PendingForm.php b/src/Utils/Testing/Form/PendingForm.php index da515272a..a4ccc4762 100644 --- a/src/Utils/Testing/Form/PendingForm.php +++ b/src/Utils/Testing/Form/PendingForm.php @@ -6,8 +6,8 @@ use Code16\Sharp\Form\SharpSingleForm; use Code16\Sharp\Utils\Entities\SharpEntityManager; use Code16\Sharp\Utils\Testing\EntityList\PendingEntityList; -use Code16\Sharp\Utils\Testing\GeneratesGlobalFilterUrl; use Code16\Sharp\Utils\Testing\IsPendingComponent; +use Code16\Sharp\Utils\Testing\SharpAssertions; use Code16\Sharp\Utils\Testing\Show\PendingShow; use Illuminate\Foundation\Testing\TestCase; use Illuminate\Testing\TestResponse; @@ -16,7 +16,6 @@ class PendingForm { use FormatsDataForUpdate; - use GeneratesGlobalFilterUrl; use IsPendingComponent; public SharpForm $form; @@ -24,7 +23,7 @@ class PendingForm protected bool $isSubsequentRequest = false; public function __construct( - /** @var TestCase $test */ + /** @var TestCase&SharpAssertions $test */ protected object $test, string $entityKey, public string|int|null $instanceId = null, @@ -36,8 +35,6 @@ public function __construct( public function create(): AssertableForm { - $this->setGlobalFilterUrlDefault(); - PHPUnit::assertNotInstanceOf(SharpSingleForm::class, $this->form); return new AssertableForm( @@ -52,8 +49,6 @@ public function create(): AssertableForm public function edit(): AssertableForm { - $this->setGlobalFilterUrlDefault(); - if (! $this->form instanceof SharpSingleForm) { PHPUnit::assertNotNull($this->instanceId, 'You can’t edit a form without an instance ID.'); } @@ -71,8 +66,6 @@ public function edit(): AssertableForm public function store(array $data): TestResponse { - $this->setGlobalFilterUrlDefault(); - PHPUnit::assertNotInstanceOf(SharpSingleForm::class, $this->form); return $this->test @@ -87,8 +80,6 @@ public function store(array $data): TestResponse public function update(array $data): TestResponse { - $this->setGlobalFilterUrlDefault(); - if (! $this->form instanceof SharpSingleForm) { PHPUnit::assertNotNull($this->instanceId, 'You can’t update a form without an instance ID.'); } diff --git a/src/Utils/Testing/GeneratesGlobalFilterUrl.php b/src/Utils/Testing/GeneratesGlobalFilterUrl.php deleted file mode 100644 index 14b910eab..000000000 --- a/src/Utils/Testing/GeneratesGlobalFilterUrl.php +++ /dev/null @@ -1,24 +0,0 @@ -globalFilter = collect((array) $globalFilterValues) - ->implode(GlobalFilters::$valuesUrlSeparator); - - return $this; - } - - private function setGlobalFilterUrlDefault(): void - { - URL::defaults(['globalFilter' => $this->globalFilter ?: GlobalFilters::$defaultKey]); - } -} diff --git a/src/Utils/Testing/HasGlobalFilters.php b/src/Utils/Testing/HasGlobalFilters.php new file mode 100644 index 000000000..9b379aa82 --- /dev/null +++ b/src/Utils/Testing/HasGlobalFilters.php @@ -0,0 +1,67 @@ +filterContainer()->findFilterHandler($globalFilterKeyOrClassName); + + if (! $filter) { + $declaredFilter = app(GlobalFilters::class)->getDeclaredFilter($globalFilterKeyOrClassName); + PHPUnit::assertNotNull($declaredFilter, "Global filter [$globalFilterKeyOrClassName] is not declared."); + PHPUnit::assertTrue($declaredFilter->authorize(), "Global filter [$globalFilterKeyOrClassName] is not authorized."); + PHPUnit::assertNotEmpty($declaredFilter->values(), "Global filter [$globalFilterKeyOrClassName] has no values."); + } + + $this->globalFilterValues[$filter->getKey()] = $value; + + $this->setGlobalFilterUrlDefault(); + + return $this; + } + + /** + * @deprecated use withSharpGlobalFilter() instead + */ + public function withSharpGlobalFilterValues(array|string $globalFilterValues): static + { + $this->globalFilterSegment = collect((array) $globalFilterValues) + ->implode(GlobalFilters::$valuesUrlSeparator); + + $this->setGlobalFilterUrlDefault(); + + return $this; + } + + /** + * @internal + */ + public function setGlobalFilterUrlDefault(): static + { + if ($this->globalFilterSegment) { + URL::defaults(['globalFilter' => $this->globalFilterSegment]); + } else { + $values = collect(app(GlobalFilters::class)->getFilters()) + ->map(fn (GlobalRequiredFilter $globalFilter) => $this->globalFilterValues[$globalFilter->getKey()] ?? $globalFilter->defaultValue() + ) + ->implode(GlobalFilters::$valuesUrlSeparator); + + URL::defaults(['globalFilter' => $values ?: GlobalFilters::$defaultKey]); + } + + return $this; + } +} diff --git a/src/Utils/Testing/IsPendingComponent.php b/src/Utils/Testing/IsPendingComponent.php index b981ec4ce..6f150da56 100644 --- a/src/Utils/Testing/IsPendingComponent.php +++ b/src/Utils/Testing/IsPendingComponent.php @@ -12,7 +12,6 @@ trait IsPendingComponent { use GeneratesCurrentPageUrl; - use GeneratesGlobalFilterUrl; protected function getParentUri(): string { diff --git a/src/Utils/Testing/SharpAssertions.php b/src/Utils/Testing/SharpAssertions.php index 6d2ab40ed..9b0ffd2ba 100644 --- a/src/Utils/Testing/SharpAssertions.php +++ b/src/Utils/Testing/SharpAssertions.php @@ -14,34 +14,47 @@ trait SharpAssertions { use GeneratesCurrentPageUrl; - use GeneratesGlobalFilterUrl; + use HasGlobalFilters; private BreadcrumbBuilder $breadcrumbBuilder; + public function setUpSharpAssertions(): void + { + $this->setGlobalFilterUrlDefault(); + } + public function sharpList(string $entityClassNameOrKey): PendingEntityList { + $this->setGlobalFilterUrlDefault(); + return new PendingEntityList($this, $entityClassNameOrKey); } public function sharpShow(string $entityClassNameOrKey, int|string|null $instanceId = null): PendingShow { + $this->setGlobalFilterUrlDefault(); + return new PendingShow($this, $entityClassNameOrKey, $instanceId); } public function sharpForm(string $entityClassNameOrKey, int|string|null $instanceId = null): PendingForm { + $this->setGlobalFilterUrlDefault(); + return new PendingForm($this, $entityClassNameOrKey, $instanceId); } public function sharpDashboard(string $entityClassNameOrKey): PendingDashboard { + $this->setGlobalFilterUrlDefault(); + return new PendingDashboard($this, $entityClassNameOrKey); } /** * @deprecated use withSharpBreadcrumb() instead */ - public function withSharpCurrentBreadcrumb(...$breadcrumb): self + public function withSharpCurrentBreadcrumb(...$breadcrumb): static { $this->breadcrumbBuilder = new BreadcrumbBuilder(); @@ -60,7 +73,7 @@ public function withSharpCurrentBreadcrumb(...$breadcrumb): self * @param (\Closure(BreadcrumbBuilder): BreadcrumbBuilder) $callback * @return $this */ - public function withSharpBreadcrumb(Closure $callback): self + public function withSharpBreadcrumb(Closure $callback): static { $this->breadcrumbBuilder = $callback(new BreadcrumbBuilder()); @@ -69,15 +82,12 @@ public function withSharpBreadcrumb(Closure $callback): self public function deleteFromSharpShow(string $entityClassNameOrKey, mixed $instanceId) { - $this->setGlobalFilterUrlDefault(); - $entityKey = $this->resolveEntityKey($entityClassNameOrKey); return $this ->delete( route( 'code16.sharp.show.delete', [ - 'globalFilter' => $this->globalFilter, 'parentUri' => $this->breadcrumbBuilder($entityKey)->generateUri(), 'entityKey' => $entityKey, 'instanceId' => $instanceId, @@ -88,8 +98,6 @@ public function deleteFromSharpShow(string $entityClassNameOrKey, mixed $instanc public function deleteFromSharpList(string $entityClassNameOrKey, mixed $instanceId) { - $this->setGlobalFilterUrlDefault(); - $entityKey = $this->resolveEntityKey($entityClassNameOrKey); return $this @@ -101,7 +109,6 @@ public function deleteFromSharpList(string $entityClassNameOrKey, mixed $instanc ) ->delete( route('code16.sharp.api.list.delete', [ - 'globalFilter' => $this->globalFilter, 'entityKey' => $entityKey, 'instanceId' => $instanceId, ]) @@ -110,8 +117,6 @@ public function deleteFromSharpList(string $entityClassNameOrKey, mixed $instanc public function getSharpForm(string $entityClassNameOrKey, mixed $instanceId = null) { - $this->setGlobalFilterUrlDefault(); - $entityKey = $this->resolveEntityKey($entityClassNameOrKey); return $this @@ -120,7 +125,6 @@ public function getSharpForm(string $entityClassNameOrKey, mixed $instanceId = n ? route( 'code16.sharp.form.edit', [ - 'globalFilter' => $this->globalFilter, 'parentUri' => $this->breadcrumbBuilder($entityKey)->generateUri(), 'entityKey' => $entityKey, 'instanceId' => $instanceId, @@ -129,7 +133,6 @@ public function getSharpForm(string $entityClassNameOrKey, mixed $instanceId = n : route( 'code16.sharp.form.create', [ - 'globalFilter' => $this->globalFilter, 'parentUri' => $this->breadcrumbBuilder($entityKey)->generateUri(), 'entityKey' => $entityKey, ] @@ -139,8 +142,6 @@ public function getSharpForm(string $entityClassNameOrKey, mixed $instanceId = n public function getSharpSingleForm(string $entityClassNameOrKey) { - $this->setGlobalFilterUrlDefault(); - $entityKey = $this->resolveEntityKey($entityClassNameOrKey); return $this @@ -148,7 +149,6 @@ public function getSharpSingleForm(string $entityClassNameOrKey) route( 'code16.sharp.form.edit', [ - 'globalFilter' => $this->globalFilter, 'parentUri' => $this->breadcrumbBuilder($entityKey)->generateUri(), 'entityKey' => $entityKey, ] @@ -158,15 +158,12 @@ public function getSharpSingleForm(string $entityClassNameOrKey) public function updateSharpForm(string $entityClassNameOrKey, $instanceId, array $data) { - $this->setGlobalFilterUrlDefault(); - $entityKey = $this->resolveEntityKey($entityClassNameOrKey); return $this ->post( route( 'code16.sharp.form.update', [ - 'globalFilter' => $this->globalFilter, 'parentUri' => $this->breadcrumbBuilder($entityKey)->generateUri(), 'entityKey' => $entityKey, 'instanceId' => $instanceId, @@ -178,15 +175,12 @@ public function updateSharpForm(string $entityClassNameOrKey, $instanceId, array public function updateSharpSingleForm(string $entityClassNameOrKey, array $data) { - $this->setGlobalFilterUrlDefault(); - $entityKey = $this->resolveEntityKey($entityClassNameOrKey); return $this ->post( route( 'code16.sharp.form.update', [ - 'globalFilter' => $this->globalFilter, 'parentUri' => $this->breadcrumbBuilder($entityKey)->generateUri(), 'entityKey' => $entityKey, ] @@ -197,8 +191,6 @@ public function updateSharpSingleForm(string $entityClassNameOrKey, array $data) public function getSharpShow(string $entityClassNameOrKey, $instanceId) { - $this->setGlobalFilterUrlDefault(); - $entityKey = $this->resolveEntityKey($entityClassNameOrKey); return $this @@ -206,7 +198,6 @@ public function getSharpShow(string $entityClassNameOrKey, $instanceId) route( 'code16.sharp.show.show', [ - 'globalFilter' => $this->globalFilter, 'parentUri' => $this->breadcrumbBuilder($entityKey)->generateUri(), 'entityKey' => $entityKey, 'instanceId' => $instanceId, @@ -217,8 +208,6 @@ public function getSharpShow(string $entityClassNameOrKey, $instanceId) public function storeSharpForm(string $entityClassNameOrKey, array $data) { - $this->setGlobalFilterUrlDefault(); - $entityKey = $this->resolveEntityKey($entityClassNameOrKey); return $this @@ -226,7 +215,6 @@ public function storeSharpForm(string $entityClassNameOrKey, array $data) route( 'code16.sharp.form.store', [ - 'globalFilter' => $this->globalFilter, 'parentUri' => $this->breadcrumbBuilder($entityKey)->generateUri(), 'entityKey' => $entityKey, ] @@ -242,8 +230,6 @@ public function callSharpInstanceCommandFromList( array $data = [], ?string $commandStep = null ) { - $this->setGlobalFilterUrlDefault(); - $entityKey = $this->resolveEntityKey($entityClassNameOrKey); $commandKey = class_exists($commandKeyOrClassName) @@ -273,8 +259,6 @@ public function callSharpInstanceCommandFromShow( array $data = [], ?string $commandStep = null ) { - $this->setGlobalFilterUrlDefault(); - $entityKey = $this->resolveEntityKey($entityClassNameOrKey); $commandKey = class_exists($commandKeyOrClassName) @@ -303,8 +287,6 @@ public function callSharpEntityCommandFromList( array $data = [], ?string $commandStep = null ) { - $this->setGlobalFilterUrlDefault(); - $entityKey = $this->resolveEntityKey($entityClassNameOrKey); $commandKey = class_exists($commandKeyOrClassName) @@ -322,7 +304,7 @@ public function callSharpEntityCommandFromList( ); } - public function loginAsSharpUser($user): self + public function loginAsSharpUser($user): static { return $this->actingAs($user, sharp()->config()->get('auth.guard') ?: config('auth.defaults.guard')); } diff --git a/src/Utils/Testing/Show/PendingShow.php b/src/Utils/Testing/Show/PendingShow.php index 3ac412f6d..dc1d49c37 100644 --- a/src/Utils/Testing/Show/PendingShow.php +++ b/src/Utils/Testing/Show/PendingShow.php @@ -11,21 +11,20 @@ use Code16\Sharp\Utils\Testing\Dashboard\PendingDashboard; use Code16\Sharp\Utils\Testing\EntityList\PendingEntityList; use Code16\Sharp\Utils\Testing\Form\PendingForm; -use Code16\Sharp\Utils\Testing\GeneratesGlobalFilterUrl; use Code16\Sharp\Utils\Testing\IsPendingComponent; +use Code16\Sharp\Utils\Testing\SharpAssertions; use Illuminate\Foundation\Testing\TestCase; class PendingShow { use FormatsDataForCommand; - use GeneratesGlobalFilterUrl; use IsPendingComponent; public SharpShow $show; public string $entityKey; public function __construct( - /** @var TestCase $test */ + /** @var TestCase&SharpAssertions $test */ protected object $test, string $entityKey, public string|int|null $instanceId = null, @@ -52,8 +51,6 @@ public function sharpDashboardField(string $entityClassNameOrKey): PendingDashbo public function get(): AssertableShow { - $this->setGlobalFilterUrlDefault(); - return new AssertableShow( $this->test ->get($this->show instanceof SharpSingleShow @@ -71,8 +68,6 @@ public function get(): AssertableShow public function instanceCommand(string $commandKeyOrClassName): PendingCommand { - $this->setGlobalFilterUrlDefault(); - $commandKey = class_exists($commandKeyOrClassName) ? class_basename($commandKeyOrClassName) : $commandKeyOrClassName; diff --git a/tests/Http/SharpAssertionsHttpTest.php b/tests/Http/SharpAssertionsHttpTest.php index 5cc3df191..7fa9cb154 100644 --- a/tests/Http/SharpAssertionsHttpTest.php +++ b/tests/Http/SharpAssertionsHttpTest.php @@ -19,12 +19,16 @@ use Code16\Sharp\Tests\Fixtures\Sharp\PersonShow; use Code16\Sharp\Tests\Fixtures\Sharp\SinglePersonShow; use Code16\Sharp\Tests\Fixtures\Sharp\TestDashboard; +use Code16\Sharp\Tests\ResetUrlDefaults; use Code16\Sharp\Utils\Fields\FieldsContainer; use Code16\Sharp\Utils\Testing\SharpAssertions; use Illuminate\Http\UploadedFile; use Illuminate\Testing\Fluent\AssertableJson; +use Illuminate\Testing\TestResponse; -pest()->use(SharpAssertions::class); +pest() + ->use(ResetUrlDefaults::class) + ->use(SharpAssertions::class); beforeEach(function () { login(); @@ -791,3 +795,59 @@ public function execute(array $data = []): array ->dashboardCommand('cmd-form')->getForm()->post(['action' => 'info']) ->assertReturnsInfo('dashboard'); }); + +it('set default global filter', function () { + fakeGlobalFilter(); + + $this + ->sharpList(PersonEntity::class) + ->get() + ->assertOk() + ->tap(fn (TestResponse $response) => expect($response->baseRequest->route('globalFilter'))->toEqual('two') + ); + + $this + ->sharpShow(PersonEntity::class, 1) + ->get() + ->assertOk() + ->tap(fn (TestResponse $response) => expect($response->baseRequest->route('globalFilter'))->toEqual('two') + ); + + $this + ->sharpForm(PersonEntity::class) + ->create() + ->assertOk() + ->tap(fn (TestResponse $response) => expect($response->baseRequest->route('globalFilter'))->toEqual('two') + ); +}); + +it('set specified global filter', function () { + fakeGlobalFilter('test'); + + $this->withSharpGlobalFilter('test', 'one'); + + $this + ->sharpList(PersonEntity::class) + ->get() + ->assertOk() + ->tap(fn (TestResponse $response) => expect($response->baseRequest->route('globalFilter'))->toEqual('one') + ); + + $this->withSharpGlobalFilter('test', 'two'); + + $this + ->sharpShow(PersonEntity::class, 1) + ->get() + ->assertOk() + ->tap(fn (TestResponse $response) => expect($response->baseRequest->route('globalFilter'))->toEqual('two') + ); + + $this->withSharpGlobalFilter('test', 'one'); + + $this + ->sharpForm(PersonEntity::class) + ->create() + ->assertOk() + ->tap(fn (TestResponse $response) => expect($response->baseRequest->route('globalFilter'))->toEqual('one') + ); +}); diff --git a/tests/ResetUrlDefaults.php b/tests/ResetUrlDefaults.php new file mode 100644 index 000000000..c08e4b01c --- /dev/null +++ b/tests/ResetUrlDefaults.php @@ -0,0 +1,13 @@ + null]); + } +}