diff --git a/tests/Column/DataColumnTest.php b/tests/Column/DataColumnTest.php
index 1bfe6117f..6137a9f6b 100644
--- a/tests/Column/DataColumnTest.php
+++ b/tests/Column/DataColumnTest.php
@@ -10,7 +10,9 @@
use Yiisoft\Definitions\Exception\InvalidConfigException;
use Yiisoft\Definitions\Exception\NotInstantiableException;
use Yiisoft\Factory\NotFoundException;
+use Yiisoft\Validator\Rule\Email;
use Yiisoft\Yii\DataView\Column\DataColumn;
+use Yiisoft\Yii\DataView\Filter\Factory\EqualsFilterFactory;
use Yiisoft\Yii\DataView\GridView;
use Yiisoft\Yii\DataView\Tests\Support\Assert;
use Yiisoft\Yii\DataView\Tests\Support\TestTrait;
@@ -698,7 +700,7 @@ public function testFilterWithValidationError(): void
new DataColumn(
'email',
filter: true,
- filterValidation: new \Yiisoft\Validator\Rule\Email()
+ filterValidation: new Email()
),
)
->id('w1-grid')
@@ -745,7 +747,7 @@ public function testCustomFilterFactory(): void
new DataColumn(
'status',
filter: true,
- filterFactory: new \Yiisoft\Yii\DataView\Filter\Factory\EqualsFilterFactory()
+ filterFactory: new EqualsFilterFactory()
),
)
->id('w1-grid')
diff --git a/tests/Column/RadioColumnRendererTest.php b/tests/Column/RadioColumnRendererTest.php
index f36847bd8..b39a7bc0a 100644
--- a/tests/Column/RadioColumnRendererTest.php
+++ b/tests/Column/RadioColumnRendererTest.php
@@ -241,53 +241,6 @@ public function testRenderFooterWithContent(): void
$this->assertSame('Footer content', $result->getContent()[0]);
}
- public function testRenderFooterWithoutContent(): void
- {
- $column = new RadioColumn();
- $cell = new Cell();
- $translator = Mock::translator('en');
-
- $context = new GlobalContext(
- dataReader: $this->dataReader,
- pathArguments: [],
- queryParameters: [],
- translator: $translator,
- translationCategory: 'test'
- );
-
- $renderer = new RadioColumnRenderer();
- $result = $renderer->renderFooter($column, $cell, $context);
-
- $this->assertEmpty($result->getContent());
- }
-
- public function testRenderBodyWithCustomContentAndEmptyAttributes(): void
- {
- $column = new RadioColumn(
- bodyAttributes: [],
- inputAttributes: [],
- content: static fn($input) => Html::div($input)->class('custom-wrapper')
- );
- $cell = new Cell();
- $data = ['id' => 1];
-
- $context = new DataContext(
- preparedDataReader: $this->dataReader,
- column: $column,
- data: $data,
- key: 1,
- index: 0
- );
-
- $renderer = new RadioColumnRenderer();
- $result = $renderer->renderBody($column, $cell, $context);
-
- $content = $result->getContent();
- $this->assertNotEmpty($content);
- $this->assertStringContainsString('
', (string)$content[0]);
- $this->assertEmpty($result->getAttributes());
- }
-
public function testRenderBodyWithCustomName(): void
{
$column = new RadioColumn(
@@ -648,12 +601,9 @@ public function testRenderBodyWithCustomHtmlContent(): void
content: static fn($input) => Html::div()
->class('input-group')
->content(
- Html::label()
- ->content(
- $input,
- Html::span('*')->class('required'),
- 'Select user'
- )
+ $input,
+ Html::span('*')->class('required'),
+ 'Select user'
)
);
$cell = new Cell();
@@ -811,7 +761,6 @@ public function testRenderBodyWithCustomContent(): void
public function testDefaultNameIsUsedWhenNotProvided(): void
{
- // Arrange
$column = new RadioColumn();
$cell = new Cell();
$data = ['id' => 42];
@@ -824,10 +773,8 @@ public function testDefaultNameIsUsedWhenNotProvided(): void
);
$renderer = new RadioColumnRenderer();
- // Act
$result = $renderer->renderBody($column, $cell, $context);
- // Assert
$content = $result->getContent();
$this->assertStringContainsString('name="radio-selection"', (string)$content[0]);
}
@@ -892,7 +839,7 @@ public function testRenderBodyWithEmptyContentClosure(): void
public function testRenderBodyWithContextInContentClosure(): void
{
$column = new RadioColumn(
- content: static fn($input, $context) => (string)$input . ' Item ' . $context->index
+ content: static fn($input, $context) => $input . ' Item ' . $context->index
);
$cell = new Cell();
$data = ['id' => 42];
@@ -1115,7 +1062,6 @@ public function testRenderBodyWithCustomValueAndChecked(): void
public function testEmptyNameAttributeIsPreserved(): void
{
- // Arrange
$column = new RadioColumn(
inputAttributes: [
'name' => '',
@@ -1135,17 +1081,14 @@ public function testEmptyNameAttributeIsPreserved(): void
);
$renderer = new RadioColumnRenderer();
- // Act
$result = $renderer->renderBody($column, $cell, $context);
- // Assert
$content = $result->getContent();
$this->assertStringContainsString('name value="1"', (string)$content[0]);
}
public function testEmptyValueAttributeIsPreserved(): void
{
- // Arrange
$column = new RadioColumn(
inputAttributes: [
'value' => '',
@@ -1165,10 +1108,8 @@ public function testEmptyValueAttributeIsPreserved(): void
);
$renderer = new RadioColumnRenderer();
- // Act
$result = $renderer->renderBody($column, $cell, $context);
- // Assert
$content = $result->getContent();
$this->assertStringContainsString('name="radio-selection" value', (string)$content[0]);
}
@@ -1253,4 +1194,230 @@ public function testRenderBodyWithInactiveStatus(): void
$this->assertStringNotContainsString('checked', (string)$content[0]);
$this->assertFalse($result->shouldEncode());
}
+
+ public function testContentClosureReceivesInputAndContext(): void
+ {
+ $expectedInput = null;
+ $expectedContext = null;
+ $column = new RadioColumn(
+ inputAttributes: [
+ 'class' => 'form-check-input',
+ 'name' => 'selection',
+ ],
+ content: static function($input, $context) use (&$expectedInput, &$expectedContext) {
+ $expectedInput = $input;
+ $expectedContext = $context;
+ return $input;
+ }
+ );
+ $cell = new Cell();
+ $data = ['id' => 42, 'name' => 'Test'];
+ $context = new DataContext(
+ preparedDataReader: $this->dataReader,
+ column: $column,
+ data: $data,
+ key: 1,
+ index: 0
+ );
+ $renderer = new RadioColumnRenderer();
+
+ $result = $renderer->renderBody($column, $cell, $context);
+
+ $this->assertNotNull($expectedInput);
+ $this->assertStringContainsString('type="radio"', (string)$expectedInput);
+ $this->assertSame($context, $expectedContext);
+ }
+
+ public function testContentClosureCanModifyInput(): void
+ {
+ $column = new RadioColumn(
+ inputAttributes: [
+ 'class' => 'form-check-input',
+ 'name' => 'selection',
+ ],
+ content: static function($input) {
+ return Html::div()
+ ->class('input-wrapper')
+ ->content(
+ $input->class('modified-input'),
+ Html::label('Select item')
+ );
+ }
+ );
+ $cell = new Cell();
+ $data = ['id' => 42];
+ $context = new DataContext(
+ preparedDataReader: $this->dataReader,
+ column: $column,
+ data: $data,
+ key: 1,
+ index: 0
+ );
+ $renderer = new RadioColumnRenderer();
+
+ $result = $renderer->renderBody($column, $cell, $context);
+
+ $content = $result->getContent();
+ $this->assertStringContainsString('class="modified-input"', (string)$content[0]);
+ $this->assertStringContainsString('class="input-wrapper"', (string)$content[0]);
+ }
+
+ public function testRenderBodyPreservesExistingInputAttributes(): void
+ {
+ $column = new RadioColumn(
+ inputAttributes: [
+ 'class' => 'custom-radio',
+ 'data-test' => 'test-value',
+ 'aria-label' => 'Select option',
+ 'name' => 'custom-name',
+ 'value' => 'custom-value',
+ ]
+ );
+ $cell = new Cell();
+ $data = ['id' => 42];
+ $context = new DataContext(
+ preparedDataReader: $this->dataReader,
+ column: $column,
+ data: $data,
+ key: 1,
+ index: 0
+ );
+ $renderer = new RadioColumnRenderer();
+
+ $result = $renderer->renderBody($column, $cell, $context);
+
+ $content = $result->getContent();
+ $this->assertStringContainsString('class="custom-radio"', (string)$content[0]);
+ $this->assertStringContainsString('data-test="test-value"', (string)$content[0]);
+ $this->assertStringContainsString('aria-label="Select option"', (string)$content[0]);
+ $this->assertStringContainsString('name="custom-name"', (string)$content[0]);
+ $this->assertStringContainsString('value="custom-value"', (string)$content[0]);
+ }
+
+ public function testRenderBodyWithCustomizedHtmlStructure(): void
+ {
+ $column = new RadioColumn(
+ inputAttributes: [
+ 'class' => 'form-check-input custom-radio',
+ 'id' => 'radio-42',
+ 'aria-label' => 'Select option',
+ ],
+ content: static function($input) {
+ return Html::div()
+ ->class('form-check custom-control')
+ ->attributes(['data-test' => 'radio-wrapper'])
+ ->content(
+ $input,
+ Html::span('✓')->class('check-mark'),
+ Html::label()
+ ->class('form-check-label')
+ ->attributes(['for' => 'radio-42'])
+ ->content('Select option')
+ );
+ }
+ );
+ $cell = new Cell();
+ $data = ['id' => 42];
+ $context = new DataContext(
+ preparedDataReader: $this->dataReader,
+ column: $column,
+ data: $data,
+ key: 1,
+ index: 0
+ );
+ $renderer = new RadioColumnRenderer();
+
+ $result = $renderer->renderBody($column, $cell, $context);
+
+ $content = $result->getContent();
+ $this->assertStringContainsString('form-check-input', (string)$content[0]);
+ $this->assertStringContainsString('custom-radio', (string)$content[0]);
+ $this->assertStringContainsString('for="radio-42"', (string)$content[0]);
+ $this->assertStringContainsString('id="radio-42"', (string)$content[0]);
+ $this->assertStringContainsString('check-mark', (string)$content[0]);
+ $this->assertStringContainsString('Select option', (string)$content[0]);
+ }
+
+ public function testRenderBodyWithCustomizedHtmlStructureAndAttributes(): void
+ {
+ $column = new RadioColumn(
+ inputAttributes: [
+ 'class' => 'form-check-input custom-radio',
+ 'id' => 'radio-42',
+ 'aria-label' => 'Select option',
+ 'data-test' => 'test-value',
+ ],
+ content: static function($input) {
+ return Html::div()
+ ->class('form-check custom-control')
+ ->attributes([
+ 'data-test' => 'radio-wrapper',
+ 'data-user-id' => '42',
+ ])
+ ->content(
+ $input,
+ Html::span('✓')->class('check-mark'),
+ Html::label()
+ ->class('form-check-label')
+ ->attributes(['for' => 'radio-42'])
+ ->content('Select option')
+ );
+ }
+ );
+ $cell = new Cell();
+ $data = ['id' => 42];
+ $context = new DataContext(
+ preparedDataReader: $this->dataReader,
+ column: $column,
+ data: $data,
+ key: 1,
+ index: 0
+ );
+ $renderer = new RadioColumnRenderer();
+
+ $result = $renderer->renderBody($column, $cell, $context);
+
+ $content = $result->getContent();
+ $this->assertStringContainsString('form-check-input', (string)$content[0]);
+ $this->assertStringContainsString('custom-radio', (string)$content[0]);
+ $this->assertStringContainsString('data-test="test-value"', (string)$content[0]);
+ $this->assertStringContainsString('data-user-id="42"', (string)$content[0]);
+ $this->assertStringContainsString('for="radio-42"', (string)$content[0]);
+ $this->assertStringContainsString('id="radio-42"', (string)$content[0]);
+ $this->assertStringContainsString('check-mark', (string)$content[0]);
+ $this->assertStringContainsString('Select option', (string)$content[0]);
+ }
+
+ public function testRenderBodyWithDataFromContext(): void
+ {
+ $column = new RadioColumn(
+ inputAttributes: ['class' => 'form-check-input'],
+ content: static function($input, $context) {
+ return Html::div()
+ ->class('form-check')
+ ->content(
+ $input,
+ Html::label()
+ ->class('form-check-label')
+ ->content($context->data['name'])
+ );
+ }
+ );
+ $cell = new Cell();
+ $data = ['id' => 42, 'name' => 'Test User'];
+ $context = new DataContext(
+ preparedDataReader: $this->dataReader,
+ column: $column,
+ data: $data,
+ key: 1,
+ index: 0
+ );
+ $renderer = new RadioColumnRenderer();
+
+ $result = $renderer->renderBody($column, $cell, $context);
+
+ $content = $result->getContent();
+ $this->assertStringContainsString('Test User', (string)$content[0]);
+ $this->assertStringContainsString('class="form-check-label"', (string)$content[0]);
+ }
}
diff --git a/tests/GridView/ImmutableTest.php b/tests/GridView/ImmutableTest.php
index 13adbc815..dfe2e5ba1 100644
--- a/tests/GridView/ImmutableTest.php
+++ b/tests/GridView/ImmutableTest.php
@@ -10,6 +10,7 @@
use Yiisoft\Definitions\Exception\InvalidConfigException;
use Yiisoft\Definitions\Exception\NotInstantiableException;
use Yiisoft\Factory\NotFoundException;
+use Yiisoft\Validator\Result;
use Yiisoft\Yii\DataView;
use Yiisoft\Yii\DataView\Column\DataColumn;
use Yiisoft\Yii\DataView\Pagination\OffsetPagination;
@@ -106,7 +107,7 @@ private function createBaseListView(): DataView\BaseListView
return new class () extends DataView\BaseListView {
public function renderItems(
array $items,
- \Yiisoft\Validator\Result $filterValidationResult,
+ Result $filterValidationResult,
?ReadableDataInterface $preparedDataReader,
): string {
return '';
diff --git a/tests/GridView/TranslatorTest.php b/tests/GridView/TranslatorTest.php
index ab540ec17..5d362c2a1 100644
--- a/tests/GridView/TranslatorTest.php
+++ b/tests/GridView/TranslatorTest.php
@@ -11,6 +11,7 @@
use Yiisoft\Definitions\Reference;
use Yiisoft\Di\Container;
use Yiisoft\Di\ContainerConfig;
+use Yiisoft\Factory\NotFoundException;
use Yiisoft\Translator\Translator;
use Yiisoft\Translator\TranslatorInterface;
use Yiisoft\Validator\Validator;
@@ -153,7 +154,7 @@ public function testEmptyTextTranslatorWithLocaleRussian(): void
/**
* @throws InvalidConfigException
- * @throws \Yiisoft\Factory\NotFoundException
+ * @throws NotFoundException
* @throws NotInstantiableException
* @throws CircularReferenceException
*/
@@ -204,7 +205,7 @@ public function testSummaryTranslatorWithLocaleDefault(): void
/**
* @throws InvalidConfigException
- * @throws \Yiisoft\Factory\NotFoundException
+ * @throws NotFoundException
* @throws NotInstantiableException
* @throws CircularReferenceException
*/
@@ -257,7 +258,7 @@ public function testSummaryTranslatorWithLocaleSpanish(): void
/**
* @throws InvalidConfigException
- * @throws \Yiisoft\Factory\NotFoundException
+ * @throws NotFoundException
* @throws NotInstantiableException
* @throws CircularReferenceException
*/
diff --git a/tests/Pagination/OffsetPaginationTest.php b/tests/Pagination/OffsetPaginationTest.php
index 53d85dc0a..327b032f7 100644
--- a/tests/Pagination/OffsetPaginationTest.php
+++ b/tests/Pagination/OffsetPaginationTest.php
@@ -4,30 +4,65 @@
namespace Yiisoft\Yii\DataView\Tests\Pagination;
+use InvalidArgumentException;
use PHPUnit\Framework\TestCase;
use Yiisoft\Definitions\Exception\CircularReferenceException;
use Yiisoft\Definitions\Exception\InvalidConfigException;
use Yiisoft\Definitions\Exception\NotInstantiableException;
use Yiisoft\Factory\NotFoundException;
-use Yiisoft\Yii\DataView\Pagination\PaginatorNotSetException;
+use Yiisoft\Yii\DataView\Column\DataColumn;
use Yiisoft\Yii\DataView\GridView;
use Yiisoft\Yii\DataView\Pagination\OffsetPagination;
+use Yiisoft\Yii\DataView\Pagination\PaginatorNotSetException;
use Yiisoft\Yii\DataView\Tests\Support\Assert;
use Yiisoft\Yii\DataView\Tests\Support\TestTrait;
+/**
+ * @psalm-suppress PropertyNotSetInConstructor
+ */
final class OffsetPaginationTest extends TestCase
{
use TestTrait;
+ private const PAGE_SIZE = 10;
+ private const TOTAL_ITEMS = 30;
+
+ /**
+ * @return array
+ */
+ private function createTestData(): array
+ {
+ return array_map(
+ static fn (int $i): array => ['id' => $i, 'value' => "Item $i"],
+ range(1, self::TOTAL_ITEMS)
+ );
+ }
+
/**
+ * @param array $data
+ */
+ private function createGridView(array $data, OffsetPagination $pagination): string
+ {
+ return GridView::widget()
+ ->id('w1-grid')
+ ->dataReader($this->createOffsetPaginator($data, self::PAGE_SIZE))
+ ->columns(
+ new DataColumn(property: 'id'),
+ new DataColumn(property: 'value')
+ )
+ ->paginationWidget($pagination)
+ ->render();
+ }
+
+ /**
+ * @throws CircularReferenceException
* @throws InvalidConfigException
- * @throws NotFoundException
* @throws NotInstantiableException
- * @throws CircularReferenceException
+ * @throws NotFoundException
*/
- public function testRenderPaginatorEmptyData(): void
+ public function testEmptyData(): void
{
- $offsetPaginator = $this->createOffsetPaginator([], 10);
+ $offsetPaginator = $this->createOffsetPaginator([], self::PAGE_SIZE);
Assert::equalsWithoutLE(
<<expectException(PaginatorNotSetException::class);
- $this->expectExceptionMessage('Failed to create widget because "paginator" is not set.');
- Assert::invokeMethod($pagination, 'getPaginator');
+ $pagination->render();
+ }
+
+ public function testEmptyContainerTag(): void
+ {
+ $pagination = OffsetPagination::widget();
+
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage('Tag name cannot be empty.');
+ $pagination->containerTag('');
+ }
+
+ public function testEmptyListTag(): void
+ {
+ $pagination = OffsetPagination::widget();
+
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage('Tag name cannot be empty.');
+ $pagination->listTag('');
+ }
+
+ public function testEmptyItemTag(): void
+ {
+ $pagination = OffsetPagination::widget();
+
+ $this->expectException(InvalidArgumentException::class);
+ $this->expectExceptionMessage('Tag name cannot be empty.');
+ $pagination->itemTag('');
+ }
+
+ /**
+ * @throws CircularReferenceException
+ * @throws InvalidConfigException
+ * @throws NotInstantiableException
+ * @throws NotFoundException
+ */
+ public function testCustomAttributes(): void
+ {
+ $pagination = OffsetPagination::widget()
+ ->containerAttributes(['class' => 'container'])
+ ->linkAttributes(['class' => 'link'])
+ ->currentLinkClass('current')
+ ->disabledLinkClass('inactive')
+ ->maxNavLinkCount(5);
+
+ $html = $this->createGridView($this->createTestData(), $pagination);
+
+ $this->assertStringContainsString('class="container"', $html);
+ $this->assertStringContainsString('class="link inactive"', $html);
+ $this->assertStringContainsString('class="link current"', $html);
+ }
+
+ /**
+ * @throws CircularReferenceException
+ * @throws InvalidConfigException
+ * @throws NotInstantiableException
+ * @throws NotFoundException
+ */
+ public function testCustomLabels(): void
+ {
+ $pagination = OffsetPagination::widget()
+ ->labelFirst('First')
+ ->labelLast('Last')
+ ->labelPrevious('Prev')
+ ->labelNext('Next');
+
+ $html = $this->createGridView($this->createTestData(), $pagination);
+
+ $this->assertStringContainsString('First', $html);
+ $this->assertStringContainsString('Last', $html);
+ $this->assertStringContainsString('Prev', $html);
+ $this->assertStringContainsString('Next', $html);
+ }
+
+ /**
+ * @throws CircularReferenceException
+ * @throws InvalidConfigException
+ * @throws NotInstantiableException
+ * @throws NotFoundException
+ */
+ public function testCustomTags(): void
+ {
+ $pagination = OffsetPagination::widget()
+ ->containerTag('div')
+ ->listTag('ul')
+ ->itemTag('li');
+
+ $html = $this->createGridView($this->createTestData(), $pagination);
+
+ $this->assertStringContainsString('assertStringContainsString('
assertStringContainsString('