first commit

This commit is contained in:
2026-01-25 18:18:09 +08:00
commit 509312e604
8136 changed files with 2349298 additions and 0 deletions

View File

@ -0,0 +1,338 @@
<?php
declare(strict_types=1);
namespace yiiunit\extensions\bootstrap5;
use yii\base\DynamicModel;
use yii\bootstrap5\Accordion;
use yii\widgets\ActiveForm;
/**
* @group bootstrap5
*/
class AccordionTest extends TestCase
{
public function testRender()
{
Accordion::$counter = 0;
$output = Accordion::widget([
'items' => [
[
'label' => 'Collapsible Group Item #1',
'content' => [
'test content1',
'test content2',
],
],
[
'label' => 'Collapsible Group Item #2',
'content' => 'Das ist das Haus vom Nikolaus',
'contentOptions' => [
'class' => 'testContentOptions',
],
'options' => [
'class' => 'testClass',
'id' => 'testId',
],
'footer' => 'Footer',
],
[
'label' => '<h1>Collapsible Group Item #3</h1>',
'content' => [
'<h2>test content1</h2>',
'<h2>test content2</h2>',
],
'contentOptions' => [
'class' => 'testContentOptions2',
],
'options' => [
'class' => 'testClass2',
'id' => 'testId2',
],
'encode' => false,
'footer' => 'Footer2',
],
[
'label' => '<h1>Collapsible Group Item #4</h1>',
'content' => [
'<h2>test content1</h2>',
'<h2>test content2</h2>',
],
'contentOptions' => [
'class' => 'testContentOptions3',
],
'options' => [
'class' => 'testClass3',
'id' => 'testId3',
],
'encode' => true,
'footer' => 'Footer3',
],
],
]);
$this->assertEqualsWithoutLE(<<<HTML
<div id="w0" class="accordion">
<div class="accordion-item"><div id="w0-collapse0-heading" class="accordion-header"><h5 class="mb-0"><button type="button" id="w1" class="accordion-button" data-bs-toggle="collapse" data-bs-target="#w0-collapse0" aria-expanded="true" aria-controls="w0-collapse0">Collapsible Group Item #1</button>
</h5></div>
<div id="w0-collapse0" class="collapse show" aria-labelledby="w0-collapse0-heading" data-bs-parent="#w0">
<ul class="list-group">
<li class="list-group-item">test content1</li>
<li class="list-group-item">test content2</li>
</ul>
</div></div>
<div id="testId" class="testClass accordion-item"><div id="w0-collapse1-heading" class="accordion-header"><h5 class="mb-0"><button type="button" id="w2" class="accordion-button collapsed" data-bs-toggle="collapse" data-bs-target="#w0-collapse1" aria-expanded="false" aria-controls="w0-collapse1">Collapsible Group Item #2</button>
</h5></div>
<div id="w0-collapse1" class="testContentOptions collapse" aria-labelledby="w0-collapse1-heading" data-bs-parent="#w0">
<div class="accordion-body">Das ist das Haus vom Nikolaus</div>
<div class="accordion-footer">Footer</div>
</div></div>
<div id="testId2" class="testClass2 accordion-item"><div id="w0-collapse2-heading" class="accordion-header"><h5 class="mb-0"><button type="button" id="w3" class="accordion-button collapsed" data-bs-toggle="collapse" data-bs-target="#w0-collapse2" aria-expanded="false" aria-controls="w0-collapse2"><h1>Collapsible Group Item #3</h1></button>
</h5></div>
<div id="w0-collapse2" class="testContentOptions2 collapse" aria-labelledby="w0-collapse2-heading" data-bs-parent="#w0">
<ul class="list-group">
<li class="list-group-item"><h2>test content1</h2></li>
<li class="list-group-item"><h2>test content2</h2></li>
</ul>
<div class="accordion-footer">Footer2</div>
</div></div>
<div id="testId3" class="testClass3 accordion-item"><div id="w0-collapse3-heading" class="accordion-header"><h5 class="mb-0"><button type="button" id="w4" class="accordion-button collapsed" data-bs-toggle="collapse" data-bs-target="#w0-collapse3" aria-expanded="false" aria-controls="w0-collapse3">&lt;h1&gt;Collapsible Group Item #4&lt;/h1&gt;</button>
</h5></div>
<div id="w0-collapse3" class="testContentOptions3 collapse" aria-labelledby="w0-collapse3-heading" data-bs-parent="#w0">
<ul class="list-group">
<li class="list-group-item"><h2>test content1</h2></li>
<li class="list-group-item"><h2>test content2</h2></li>
</ul>
<div class="accordion-footer">Footer3</div>
</div></div>
</div>
HTML
, $output);
}
public function testLabelKeys()
{
ob_start();
$form = ActiveForm::begin([
'action' => '/something',
]);
ActiveForm::end();
ob_end_clean();
Accordion::$counter = 0;
$output = Accordion::widget([
'items' => [
'Item1' => 'Content1',
'Item2' => [
'content' => 'Content2',
],
[
'label' => 'Item3',
'content' => 'Content3',
],
'FormField' => $form->field(new DynamicModel(['test']), 'test', [
'template' => '{input}',
]),
],
]);
$this->assertEqualsWithoutLE(<<<HTML
<div id="w0" class="accordion">
<div class="accordion-item"><div id="w0-collapse0-heading" class="accordion-header"><h5 class="mb-0"><button type="button" id="w1" class="accordion-button" data-bs-toggle="collapse" data-bs-target="#w0-collapse0" aria-expanded="true" aria-controls="w0-collapse0">Item1</button>
</h5></div>
<div id="w0-collapse0" class="collapse show" aria-labelledby="w0-collapse0-heading" data-bs-parent="#w0">
<div class="accordion-body">Content1</div>
</div></div>
<div class="accordion-item"><div id="w0-collapse1-heading" class="accordion-header"><h5 class="mb-0"><button type="button" id="w2" class="accordion-button collapsed" data-bs-toggle="collapse" data-bs-target="#w0-collapse1" aria-expanded="false" aria-controls="w0-collapse1">Item2</button>
</h5></div>
<div id="w0-collapse1" class="collapse" aria-labelledby="w0-collapse1-heading" data-bs-parent="#w0">
<div class="accordion-body">Content2</div>
</div></div>
<div class="accordion-item"><div id="w0-collapse2-heading" class="accordion-header"><h5 class="mb-0"><button type="button" id="w3" class="accordion-button collapsed" data-bs-toggle="collapse" data-bs-target="#w0-collapse2" aria-expanded="false" aria-controls="w0-collapse2">Item3</button>
</h5></div>
<div id="w0-collapse2" class="collapse" aria-labelledby="w0-collapse2-heading" data-bs-parent="#w0">
<div class="accordion-body">Content3</div>
</div></div>
<div class="accordion-item"><div id="w0-collapse3-heading" class="accordion-header"><h5 class="mb-0"><button type="button" id="w4" class="accordion-button collapsed" data-bs-toggle="collapse" data-bs-target="#w0-collapse3" aria-expanded="false" aria-controls="w0-collapse3">FormField</button>
</h5></div>
<div id="w0-collapse3" class="collapse" aria-labelledby="w0-collapse3-heading" data-bs-parent="#w0">
<div class="accordion-body"><div class="form-group field-dynamicmodel-test">
<input type="text" id="dynamicmodel-test" class="form-control" name="DynamicModel[test]">
</div></div>
</div></div>
</div>
HTML
, $output);
}
public function testExpandOptions()
{
Accordion::$counter = 0;
$output = Accordion::widget([
'items' => [
'Item1' => 'Content1',
'Item2' => [
'content' => 'Content2',
'expand' => true,
],
],
]);
$this->assertEqualsWithoutLE(<<<HTML
<div id="w0" class="accordion">
<div class="accordion-item"><div id="w0-collapse0-heading" class="accordion-header"><h5 class="mb-0"><button type="button" id="w1" class="accordion-button collapsed" data-bs-toggle="collapse" data-bs-target="#w0-collapse0" aria-expanded="false" aria-controls="w0-collapse0">Item1</button>
</h5></div>
<div id="w0-collapse0" class="collapse" aria-labelledby="w0-collapse0-heading" data-bs-parent="#w0">
<div class="accordion-body">Content1</div>
</div></div>
<div class="accordion-item"><div id="w0-collapse1-heading" class="accordion-header"><h5 class="mb-0"><button type="button" id="w2" class="accordion-button" data-bs-toggle="collapse" data-bs-target="#w0-collapse1" aria-expanded="true" aria-controls="w0-collapse1">Item2</button>
</h5></div>
<div id="w0-collapse1" class="collapse show" aria-labelledby="w0-collapse1-heading" data-bs-parent="#w0">
<div class="accordion-body">Content2</div>
</div></div>
</div>
HTML
, $output);
}
public function invalidItemsProvider()
{
return [
[['content']], // only content without label key
[[[]]], // only content array without label
[[[
'content' => 'test',
]]], // only content array without label
];
}
/**
* @dataProvider invalidItemsProvider
*/
public function testMissingLabel($items)
{
$this->expectException(\yii\base\InvalidConfigException::class);
Accordion::widget([
'items' => $items,
]);
}
/**
* @see https://github.com/yiisoft/yii2/issues/8357
*/
public function testRenderObject()
{
$template = [
'template' => '{input}',
];
ob_start();
$form = ActiveForm::begin([
'action' => '/something',
]);
ActiveForm::end();
ob_end_clean();
$model = new data\Singer();
Accordion::$counter = 0;
$output = Accordion::widget([
'items' => [
[
'label' => 'Collapsible Group Item #1',
'content' => $form->field($model, 'firstName', $template),
],
],
]);
$this->assertEqualsWithoutLE(<<<HTML
<div id="w0" class="accordion">
<div class="accordion-item"><div id="w0-collapse0-heading" class="accordion-header"><h5 class="mb-0"><button type="button" id="w1" class="accordion-button" data-bs-toggle="collapse" data-bs-target="#w0-collapse0" aria-expanded="true" aria-controls="w0-collapse0">Collapsible Group Item #1</button>
</h5></div>
<div id="w0-collapse0" class="collapse show" aria-labelledby="w0-collapse0-heading" data-bs-parent="#w0">
<div class="accordion-body"><div class="form-group field-singer-firstname">
<input type="text" id="singer-firstname" class="form-control" name="Singer[firstName]">
</div></div>
</div></div>
</div>
HTML
, $output);
}
public function testAutoCloseItems()
{
$items = [
[
'label' => 'Item 1',
'content' => 'Content 1',
],
[
'label' => 'Item 2',
'content' => 'Content 2',
],
];
$output = Accordion::widget([
'items' => $items,
]);
$this->assertStringContainsString('data-bs-parent="', $output);
$output = Accordion::widget([
'autoCloseItems' => false,
'items' => $items,
]);
$this->assertStringNotContainsString('data-bs-parent="', $output);
}
public function testItemToggleTag()
{
$items = [
[
'label' => 'Item 1',
'content' => 'Content 1',
],
[
'label' => 'Item 2',
'content' => 'Content 2',
],
];
Accordion::$counter = 0;
$output = Accordion::widget([
'items' => $items,
'itemToggleOptions' => [
'tag' => 'a',
'class' => 'custom-toggle',
],
]);
$this->assertStringContainsString('<h5 class="mb-0"><a type="button" class="custom-toggle" href="#w0-collapse0" ', $output);
$this->assertStringNotContainsString('<button', $output);
$output = Accordion::widget([
'items' => $items,
'itemToggleOptions' => [
'tag' => 'a',
'class' => [
'widget' => 'custom-toggle',
],
],
]);
$this->assertStringContainsString('<h5 class="mb-0"><a type="button" class="custom-toggle" href="#w1-collapse0" ', $output);
$this->assertStringNotContainsString('collapse-toggle', $output);
}
}

View File

@ -0,0 +1,270 @@
<?php
declare(strict_types=1);
namespace yiiunit\extensions\bootstrap5;
use Yii;
use yii\base\DynamicModel;
use yii\bootstrap5\ActiveField;
use yii\bootstrap5\ActiveForm;
use yii\bootstrap5\Html;
use yii\helpers\UnsetArrayValue;
class ActiveFieldDefaultFormCheckTest extends TestCase
{
/**
* @var ActiveField
*/
private $_activeField;
/**
* @var DynamicModel
*/
private $_helperModel;
/**
* @var ActiveForm
*/
private $_helperForm;
/**
* @var string
*/
private $_attributeName = 'attributeName';
public function testDefaultCheckboxByConfig()
{
Html::$counter = 0;
$this->_activeField->inline = true;
$html = $this->_activeField->checkbox()->render();
$expectedHtml = <<<HTML
<div class="mb-3 field-dynamicmodel-attributename">
<div class="form-check">
<input type="hidden" name="DynamicModel[attributeName]" value="0"><input type="checkbox" id="dynamicmodel-attributename" class="form-check-input" name="DynamicModel[attributeName]" value="1">
<label class="form-check-label" for="dynamicmodel-attributename">Attribute Name</label>
<div class="invalid-feedback"></div>
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expectedHtml, $html);
}
public function testDefaultRadioByConfig()
{
Html::$counter = 0;
$this->_activeField->inline = true;
$html = $this->_activeField->radio()->render();
$expectedHtml = <<<HTML
<div class="mb-3 field-dynamicmodel-attributename">
<div class="form-check">
<input type="hidden" name="DynamicModel[attributeName]" value="0"><input type="radio" id="dynamicmodel-attributename" class="form-check-input" name="DynamicModel[attributeName]" value="1">
<label class="form-check-label" for="dynamicmodel-attributename">Attribute Name</label>
<div class="invalid-feedback"></div>
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expectedHtml, $html);
}
public function testDefaultCheckboxListByConfig()
{
Html::$counter = 0;
$html = $this->_activeField->checkboxList([
1 => 'name1',
2 => 'name2',
])->render();
$expectedHtml = <<<HTML
<div class="mb-3 field-dynamicmodel-attributename">
<label class="form-label">Attribute Name</label>
<input type="hidden" name="DynamicModel[attributeName]" value=""><div id="dynamicmodel-attributename"><div class="form-check">
<input type="checkbox" id="i0" class="form-check-input" name="DynamicModel[attributeName][]" value="1">
<label class="form-check-label" for="i0">name1</label>
</div>
<div class="form-check">
<input type="checkbox" id="i1" class="form-check-input" name="DynamicModel[attributeName][]" value="2">
<label class="form-check-label" for="i1">name2</label>
<div class="invalid-feedback"></div>
</div>
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expectedHtml, $html);
}
public function testDefaultRadioListByConfig()
{
Html::$counter = 0;
$html = $this->_activeField->radioList([
1 => 'name1',
2 => 'name2',
])->render();
$expectedHtml = <<<HTML
<div class="mb-3 field-dynamicmodel-attributename">
<label class="form-label">Attribute Name</label>
<input type="hidden" name="DynamicModel[attributeName]" value=""><div id="dynamicmodel-attributename" role="radiogroup"><div class="form-check">
<input type="radio" id="i0" class="form-check-input" name="DynamicModel[attributeName]" value="1">
<label class="form-check-label" for="i0">name1</label>
</div>
<div class="form-check">
<input type="radio" id="i1" class="form-check-input" name="DynamicModel[attributeName]" value="2">
<label class="form-check-label" for="i1">name2</label>
<div class="invalid-feedback"></div>
</div>
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expectedHtml, $html);
}
public function testHorizontalLayout()
{
Html::$counter = 0;
ActiveForm::$counter = 0;
ob_start();
$model = new DynamicModel(['attributeName', 'checkbox', 'gridRadios']);
$form = ActiveForm::begin([
'action' => '/some-action',
'layout' => ActiveForm::LAYOUT_HORIZONTAL,
]);
echo $form->field($model, 'attributeName');
echo $form->field($model, 'checkbox')->checkbox([
'wrapperOptions' => [
'class' => [
'widget' => new UnsetArrayValue(),
],
],
]);
echo $form->field($model, 'gridRadios')->radioList([
'option1' => 'First radio',
'option2' => 'Second radio',
'option3' => 'Third radio',
]);
ActiveForm::end();
$out = ob_get_clean();
$expected = <<<HTML
<div class="mb-3 row field-dynamicmodel-attributename">
<label class="col-sm-2 col-form-label" for="dynamicmodel-attributename">Attribute Name</label>
<div class="col-sm-10">
<input type="text" id="dynamicmodel-attributename" class="form-control" name="DynamicModel[attributeName]">
<div class="invalid-feedback "></div>
</div>
</div>
HTML;
$expected2 = <<<HTML
<div class="mb-3 row field-dynamicmodel-checkbox">
<div class="col-sm-10 offset-sm-2">
<div class="form-check">
<input type="hidden" name="DynamicModel[checkbox]" value="0"><input type="checkbox" id="dynamicmodel-checkbox" class="form-check-input" name="DynamicModel[checkbox]" value="1">
<label class="form-check-label" for="dynamicmodel-checkbox">Checkbox</label>
<div class="invalid-feedback "></div>
</div>
</div>
</div>
HTML;
$expected3 = <<<HTML
<div class="mb-3 row field-dynamicmodel-gridradios">
<label class="col-sm-2 col-form-label">Grid Radios</label>
<div class="col-sm-10">
<input type="hidden" name="DynamicModel[gridRadios]" value=""><div id="dynamicmodel-gridradios" role="radiogroup"><div class="form-check">
<input type="radio" id="i0" class="form-check-input" name="DynamicModel[gridRadios]" value="option1">
<label class="form-check-label" for="i0">First radio</label>
</div>
<div class="form-check">
<input type="radio" id="i1" class="form-check-input" name="DynamicModel[gridRadios]" value="option2">
<label class="form-check-label" for="i1">Second radio</label>
</div>
<div class="form-check">
<input type="radio" id="i2" class="form-check-input" name="DynamicModel[gridRadios]" value="option3">
<label class="form-check-label" for="i2">Third radio</label>
<div class="invalid-feedback "></div>
</div>
</div>
</div>
</div>
HTML;
$this->assertContainsWithoutLE($expected, $out);
$this->assertContainsWithoutLE($expected2, $out);
$this->assertContainsWithoutLE($expected3, $out);
}
protected function setUp(): void
{
// dirty way to have Request object not throwing exception when running testHomeLinkNull()
$_SERVER['SCRIPT_FILENAME'] = 'index.php';
$_SERVER['SCRIPT_NAME'] = 'index.php';
$this->mockWebApplication([
'container' => [
'definitions' => [
'yii\bootstrap5\ActiveField' => [
'checkTemplate' => "<div class=\"form-check\">\n{input}\n{label}\n{error}\n{hint}\n</div>",
'radioTemplate' => "<div class=\"form-check\">\n{input}\n{label}\n{error}\n{hint}\n</div>",
'checkHorizontalTemplate' => "{beginWrapper}\n<div class=\"form-check\">\n{input}\n{label}\n{error}\n{hint}\n</div>\n{endWrapper}",
'radioHorizontalTemplate' => "{beginWrapper}\n<div class=\"form-check\">\n{input}\n{label}\n{error}\n{hint}\n</div>\n{endWrapper}",
'checkOptions' => [
'class' => [
'widget' => 'form-check-input',
],
'labelOptions' => [
'class' => [
'widget' => 'form-check-label',
],
],
'wrapperOptions' => [
'class' => [
'widget' => 'form-check',
],
],
],
'radioOptions' => [
'class' => [
'widget' => 'form-check-input',
],
'labelOptions' => [
'class' => [
'widget' => 'form-check-label',
],
],
'wrapperOptions' => [
'class' => [
'widget' => 'form-check',
],
],
],
],
],
],
]);
$this->_helperModel = new DynamicModel(['attributeName']);
ob_start();
$this->_helperForm = ActiveForm::begin([
'action' => '/something',
]);
ActiveForm::end();
ob_end_clean();
$this->_activeField = Yii::createObject([
'class' => 'yii\bootstrap5\ActiveField',
'form' => $this->_helperForm,
]);
$this->_activeField->model = $this->_helperModel;
$this->_activeField->attribute = $this->_attributeName;
}
}

View File

@ -0,0 +1,362 @@
<?php
declare(strict_types=1);
namespace yiiunit\extensions\bootstrap5;
use yii\base\DynamicModel;
use yii\bootstrap5\ActiveField;
use yii\bootstrap5\ActiveForm;
use yii\bootstrap5\Html;
class ActiveFieldTest extends TestCase
{
/**
* @var ActiveField
*/
private $activeField;
/**
* @var DynamicModel
*/
private $helperModel;
/**
* @var ActiveForm
*/
private $helperForm;
/**
* @var string
*/
private $attributeName = 'attributeName';
public function testFileInput()
{
$html = $this->activeField->fileInput()->render();
$expectedHtml = <<<HTML
<div class="mb-3 field-dynamicmodel-attributename">
<label class="form-label" for="dynamicmodel-attributename">Attribute Name</label>
<input type="hidden" name="DynamicModel[attributeName]" value=""><input type="file" id="dynamicmodel-attributename" class="form-control" name="DynamicModel[attributeName]">
<div class="invalid-feedback"></div>
</div>
HTML;
$this->assertEqualsWithoutLE($expectedHtml, $html);
}
public function testRangeInput()
{
$html = $this->activeField->rangeInput()->render();
$expectedHtml = <<<HTML
<div class="mb-3 field-dynamicmodel-attributename">
<label class="form-label" for="dynamicmodel-attributename">Attribute Name</label>
<input type="range" id="dynamicmodel-attributename" class="form-range" name="DynamicModel[attributeName]">
<div class="invalid-feedback"></div>
</div>
HTML;
$this->assertEqualsWithoutLE($expectedHtml, $html);
}
public function testColorInput()
{
$html = $this->activeField->colorInput()->render();
$expectedHtml = <<<HTML
<div class="mb-3 field-dynamicmodel-attributename">
<label class="form-label" for="dynamicmodel-attributename">Attribute Name</label>
<input type="color" id="dynamicmodel-attributename" class="form-control form-control-color" name="DynamicModel[attributeName]">
<div class="invalid-feedback"></div>
</div>
HTML;
$this->assertEqualsWithoutLE($expectedHtml, $html);
}
public function testRadioList()
{
$html = $this->activeField->radioList([
1 => 'name1',
2 => 'name2',
])->render();
$expectedHtml = <<<HTML
<div class="mb-3 field-dynamicmodel-attributename">
<label class="form-label">Attribute Name</label>
<input type="hidden" name="DynamicModel[attributeName]" value=""><div id="dynamicmodel-attributename" role="radiogroup"><div class="form-check">
<input type="radio" id="i0" class="form-check-input" name="DynamicModel[attributeName]" value="1">
<label class="form-check-label" for="i0">name1</label>
</div>
<div class="form-check">
<input type="radio" id="i1" class="form-check-input" name="DynamicModel[attributeName]" value="2">
<label class="form-check-label" for="i1">name2</label>
<div class="invalid-feedback"></div>
</div>
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expectedHtml, $html);
}
// Tests :
public function testRadioError()
{
$this->helperModel->addError($this->attributeName, 'Test print error message');
$html = $this->activeField->radio()->render();
$expectedHtml = <<<HTML
<div class="mb-3 field-dynamicmodel-attributename">
<div class="form-check">
<input type="hidden" name="DynamicModel[attributeName]" value="0"><input type="radio" id="dynamicmodel-attributename" class="form-check-input is-invalid" name="DynamicModel[attributeName]" value="1" aria-invalid="true">
<label class="form-check-label" for="dynamicmodel-attributename">Attribute Name</label>
<div class="invalid-feedback">Test print error message</div>
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expectedHtml, $html);
}
public function testRadioListError()
{
$this->helperModel->addError($this->attributeName, 'Test print error message');
$html = $this->activeField->radioList([
1 => 'name1',
2 => 'name2',
])->render();
$expectedHtml = <<<HTML
<div class="mb-3 field-dynamicmodel-attributename">
<label class="form-label">Attribute Name</label>
<input type="hidden" name="DynamicModel[attributeName]" value=""><div id="dynamicmodel-attributename" class="is-invalid" role="radiogroup" aria-invalid="true"><div class="form-check">
<input type="radio" id="i0" class="form-check-input" name="DynamicModel[attributeName]" value="1">
<label class="form-check-label" for="i0">name1</label>
</div>
<div class="form-check">
<input type="radio" id="i1" class="form-check-input" name="DynamicModel[attributeName]" value="2">
<label class="form-check-label" for="i1">name2</label>
<div class="invalid-feedback">Test print error message</div>
</div>
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expectedHtml, $html);
}
public function testCheckboxList()
{
$html = $this->activeField->checkboxList([
1 => 'name1',
2 => 'name2',
])->render();
$expectedHtml = <<<HTML
<div class="mb-3 field-dynamicmodel-attributename">
<label class="form-label">Attribute Name</label>
<input type="hidden" name="DynamicModel[attributeName]" value=""><div id="dynamicmodel-attributename"><div class="form-check">
<input type="checkbox" id="i0" class="form-check-input" name="DynamicModel[attributeName][]" value="1">
<label class="form-check-label" for="i0">name1</label>
</div>
<div class="form-check">
<input type="checkbox" id="i1" class="form-check-input" name="DynamicModel[attributeName][]" value="2">
<label class="form-check-label" for="i1">name2</label>
<div class="invalid-feedback"></div>
</div>
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expectedHtml, $html);
}
/**
* @test checkbox
*/
public function testCheckboxSwitch()
{
$html = $this->activeField->checkbox([
'switch' => true,
])->render();
$expectedHtml = <<<HTML
<div class="mb-3 field-dynamicmodel-attributename">
<div class="form-check form-switch">
<input type="hidden" name="DynamicModel[attributeName]" value="0"><input type="checkbox" id="dynamicmodel-attributename" class="form-check-input" name="DynamicModel[attributeName]" value="1" role="switch">
<label class="form-check-label" for="dynamicmodel-attributename">Attribute Name</label>
<div class="invalid-feedback"></div>
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expectedHtml, $html);
}
public function testCheckboxError()
{
$this->helperModel->addError($this->attributeName, 'Test print error message');
$html = $this->activeField->checkbox()->render();
$expectedHtml = <<<HTML
<div class="mb-3 field-dynamicmodel-attributename">
<div class="form-check">
<input type="hidden" name="DynamicModel[attributeName]" value="0"><input type="checkbox" id="dynamicmodel-attributename" class="form-check-input is-invalid" name="DynamicModel[attributeName]" value="1" aria-invalid="true">
<label class="form-check-label" for="dynamicmodel-attributename">Attribute Name</label>
<div class="invalid-feedback">Test print error message</div>
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expectedHtml, $html);
}
public function testCheckboxListError()
{
$this->helperModel->addError($this->attributeName, 'Test print error message');
$html = $this->activeField->checkboxList([
1 => 'name1',
2 => 'name2',
])->render();
$expectedHtml = <<<HTML
<div class="mb-3 field-dynamicmodel-attributename">
<label class="form-label">Attribute Name</label>
<input type="hidden" name="DynamicModel[attributeName]" value=""><div id="dynamicmodel-attributename" class="is-invalid" aria-invalid="true"><div class="form-check">
<input type="checkbox" id="i0" class="form-check-input" name="DynamicModel[attributeName][]" value="1">
<label class="form-check-label" for="i0">name1</label>
</div>
<div class="form-check">
<input type="checkbox" id="i1" class="form-check-input" name="DynamicModel[attributeName][]" value="2">
<label class="form-check-label" for="i1">name2</label>
<div class="invalid-feedback">Test print error message</div>
</div>
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expectedHtml, $html);
}
public function testRadioListInline()
{
$this->activeField->inline = true;
$html = $this->activeField->radioList([
1 => 'name1',
2 => 'name2',
])->render();
$expectedHtml = <<<HTML
<div class="mb-3 field-dynamicmodel-attributename">
<label class="form-label">Attribute Name</label>
<input type="hidden" name="DynamicModel[attributeName]" value=""><div id="dynamicmodel-attributename" role="radiogroup"><div class="form-check form-check-inline">
<input type="radio" id="i0" class="form-check-input" name="DynamicModel[attributeName]" value="1">
<label class="form-check-label" for="i0">name1</label>
</div>
<div class="form-check form-check-inline">
<input type="radio" id="i1" class="form-check-input" name="DynamicModel[attributeName]" value="2">
<label class="form-check-label" for="i1">name2</label>
<div class="invalid-feedback"></div>
</div>
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expectedHtml, $html);
}
public function testCheckboxListInline()
{
$this->activeField->inline = true;
$html = $this->activeField->checkboxList([
1 => 'name1',
2 => 'name2',
])->render();
$expectedHtml = <<<HTML
<div class="mb-3 field-dynamicmodel-attributename">
<label class="form-label">Attribute Name</label>
<input type="hidden" name="DynamicModel[attributeName]" value=""><div id="dynamicmodel-attributename"><div class="form-check form-check-inline">
<input type="checkbox" id="i0" class="form-check-input" name="DynamicModel[attributeName][]" value="1">
<label class="form-check-label" for="i0">name1</label>
</div>
<div class="form-check form-check-inline">
<input type="checkbox" id="i1" class="form-check-input" name="DynamicModel[attributeName][]" value="2">
<label class="form-check-label" for="i1">name2</label>
<div class="invalid-feedback"></div>
</div>
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expectedHtml, $html);
}
/**
* @see https://github.com/yiisoft/yii2-bootstrap/issues/81
*/
public function testRadioListItemOptions()
{
$content = $this->activeField->radioList([
1 => 'name1',
2 => 'name2',
], [
'itemOptions' => [
'data-attribute' => 'test',
],
])->render();
$this->assertStringContainsString('data-attribute="test"', $content);
}
/**
* @see https://github.com/yiisoft/yii2-bootstrap/issues/81
*/
public function testCheckboxListItemOptions()
{
$content = $this->activeField->checkboxList([
1 => 'name1',
2 => 'name2',
], [
'itemOptions' => [
'data-attribute' => 'test',
],
])->render();
$this->assertStringContainsString('data-attribute="test"', $content);
}
protected function setUp(): void
{
// dirty way to have Request object not throwing exception when running testHomeLinkNull()
$_SERVER['SCRIPT_FILENAME'] = "index.php";
$_SERVER['SCRIPT_NAME'] = "index.php";
parent::setUp();
Html::$counter = 0;
$this->helperModel = new DynamicModel(['attributeName']);
ob_start();
$this->helperForm = ActiveForm::begin([
'action' => '/something',
]);
ActiveForm::end();
ob_end_clean();
$this->activeField = new ActiveField([
'form' => $this->helperForm,
]);
$this->activeField->model = $this->helperModel;
$this->activeField->attribute = $this->attributeName;
}
}

View File

@ -0,0 +1,433 @@
<?php
declare(strict_types=1);
namespace yiiunit\extensions\bootstrap5;
use yii\base\DynamicModel;
use yii\bootstrap5\ActiveForm;
use yii\bootstrap5\Html;
use yiiunit\extensions\bootstrap5\data\User;
/**
* Tests for ActiveForm widget
*
* @group bootstrap5
*/
class ActiveFormTest extends TestCase
{
public function testDefaultLayout()
{
ActiveForm::$counter = 0;
ob_start();
$model = new DynamicModel(['attributeName', 'radios']);
$form = ActiveForm::begin([
'action' => '/some-action',
'layout' => ActiveForm::LAYOUT_DEFAULT,
]);
echo $form->field($model, 'attributeName');
ActiveForm::end();
$out = ob_get_clean();
$expected = <<<HTML
<div class="mb-3 field-dynamicmodel-attributename">
<label class="form-label" for="dynamicmodel-attributename">Attribute Name</label>
<input type="text" id="dynamicmodel-attributename" class="form-control" name="DynamicModel[attributeName]">
<div class="invalid-feedback"></div>
</div>
HTML;
$this->assertContainsWithoutLE($expected, $out);
}
public function testHorizontalLayout()
{
Html::$counter = 0;
ActiveForm::$counter = 0;
ob_start();
$model = new DynamicModel(['attributeName', 'checkbox', 'gridRadios']);
$form = ActiveForm::begin([
'action' => '/some-action',
'layout' => ActiveForm::LAYOUT_HORIZONTAL,
]);
echo $form->field($model, 'attributeName');
echo $form->field($model, 'checkbox')->checkbox();
echo $form->field($model, 'gridRadios')->radioList([
'option1' => 'First radio',
'option2' => 'Second radio',
'option3' => 'Third radio',
]);
ActiveForm::end();
$out = ob_get_clean();
$expected = <<<HTML
<div class="mb-3 row field-dynamicmodel-attributename">
<label class="col-sm-2 col-form-label" for="dynamicmodel-attributename">Attribute Name</label>
<div class="col-sm-10">
<input type="text" id="dynamicmodel-attributename" class="form-control" name="DynamicModel[attributeName]">
<div class="invalid-feedback "></div>
</div>
</div>
HTML;
$expected2 = <<<HTML
<div class="mb-3 row field-dynamicmodel-checkbox">
<div class="col-sm-10 offset-sm-2">
<div class="form-check">
<input type="hidden" name="DynamicModel[checkbox]" value="0"><input type="checkbox" id="dynamicmodel-checkbox" class="form-check-input" name="DynamicModel[checkbox]" value="1">
<label class="form-check-label" for="dynamicmodel-checkbox">Checkbox</label>
<div class="invalid-feedback "></div>
</div>
</div>
</div>
HTML;
$expected3 = <<<HTML
<div class="mb-3 row field-dynamicmodel-gridradios">
<label class="col-sm-2 col-form-label">Grid Radios</label>
<div class="col-sm-10">
<input type="hidden" name="DynamicModel[gridRadios]" value=""><div id="dynamicmodel-gridradios" role="radiogroup"><div class="form-check">
<input type="radio" id="i0" class="form-check-input" name="DynamicModel[gridRadios]" value="option1">
<label class="form-check-label" for="i0">First radio</label>
</div>
<div class="form-check">
<input type="radio" id="i1" class="form-check-input" name="DynamicModel[gridRadios]" value="option2">
<label class="form-check-label" for="i1">Second radio</label>
</div>
<div class="form-check">
<input type="radio" id="i2" class="form-check-input" name="DynamicModel[gridRadios]" value="option3">
<label class="form-check-label" for="i2">Third radio</label>
<div class="invalid-feedback "></div>
</div>
</div>
</div>
</div>
HTML;
$this->assertContainsWithoutLE($expected, $out);
$this->assertContainsWithoutLE($expected2, $out);
$this->assertContainsWithoutLE($expected3, $out);
}
public function testHorizontalLayoutTemplateOverride()
{
ActiveForm::$counter = 0;
ob_start();
$model = new DynamicModel(['checkboxName']);
$form = ActiveForm::begin([
'action' => '/some-action',
'layout' => ActiveForm::LAYOUT_HORIZONTAL,
]);
echo $form->field($model, 'checkboxName')->checkbox([
'template' => "<div class=\"form-check offset-lg-1 col-lg-3\">\n{input}\n{label}\n</div>\n<div class=\"col-lg-8\">{error}</div>",
]);
ActiveForm::end();
$out = ob_get_clean();
$expected = <<<HTML
<div class="form-check offset-lg-1 col-lg-3">
<input type="hidden" name="DynamicModel[checkboxName]" value="0"><input type="checkbox" id="dynamicmodel-checkboxname" class="form-check-input" name="DynamicModel[checkboxName]" value="1">
<label class="form-check-label" for="dynamicmodel-checkboxname">Checkbox Name</label>
</div>
<div class="col-lg-8"><div class="invalid-feedback "></div></div>
HTML;
$this->assertContainsWithoutLE($expected, $out);
}
public function testInlineLayout()
{
ActiveForm::$counter = 0;
ob_start();
$model = new DynamicModel(['attributeName', 'selectName', 'checkboxName']);
$form = ActiveForm::begin([
'action' => '/some-action',
'layout' => ActiveForm::LAYOUT_INLINE,
]);
echo $form->field($model, 'attributeName');
echo $form->field($model, 'selectName')->listBox([
'1' => 'One',
'2' => 'Two',
'3' => 'Three',
]);
echo $form->field($model, 'checkboxName')->checkbox();
ActiveForm::end();
$out = ob_get_clean();
$expected = <<<HTML
<div class="mb-3 field-dynamicmodel-attributename">
<label class="form-label visually-hidden" for="dynamicmodel-attributename">Attribute Name</label>
<input type="text" id="dynamicmodel-attributename" class="form-control" name="DynamicModel[attributeName]" placeholder="Attribute Name">
</div>
HTML;
$expected2 = <<<HTML
<div class="mb-3 field-dynamicmodel-selectname">
<label class="form-label" for="dynamicmodel-selectname">Select Name</label>
<input type="hidden" name="DynamicModel[selectName]" value=""><select id="dynamicmodel-selectname" class="form-select" name="DynamicModel[selectName]" size="4" placeholder>
<option value="1">One</option>
<option value="2">Two</option>
<option value="3">Three</option>
</select>
</div>
HTML;
$expected3 = <<<HTML
<div class="mb-3 field-dynamicmodel-checkboxname">
<div class="form-check">
<input type="hidden" name="DynamicModel[checkboxName]" value="0"><input type="checkbox" id="dynamicmodel-checkboxname" class="form-check-input" name="DynamicModel[checkboxName]" value="1">
<label class="form-check-label" for="dynamicmodel-checkboxname">Checkbox Name</label>
</div>
</div>
HTML;
$this->assertContainsWithoutLE('<form id="w0" class="form-inline"', $out);
$this->assertContainsWithoutLE($expected, $out);
$this->assertContainsWithoutLE($expected2, $out);
$this->assertContainsWithoutLE($expected3, $out);
}
public function testFloatingLayout()
{
ActiveForm::$counter = 0;
ob_start();
$model = new DynamicModel(['attributeName', 'selectName', 'checkboxName']);
$form = ActiveForm::begin([
'action' => '/some-action',
'layout' => ActiveForm::LAYOUT_FLOATING,
]);
echo $form->field($model, 'attributeName');
echo $form->field($model, 'selectName')->listBox([
'1' => 'One',
'2' => 'Two',
'3' => 'Three',
]);
echo $form->field($model, 'checkboxName')->checkbox();
ActiveForm::end();
$out = ob_get_clean();
$expected = <<<HTML
<div class="form-floating mt-3 field-dynamicmodel-attributename">
<input type="text" id="dynamicmodel-attributename" class="form-control" name="DynamicModel[attributeName]" placeholder="Attribute Name">
<label class="form-label" for="dynamicmodel-attributename">Attribute Name</label>
<div class="invalid-feedback"></div>
</div>
HTML;
$expected2 = <<<HTML
<div class="form-floating mt-3 field-dynamicmodel-selectname">
<input type="hidden" name="DynamicModel[selectName]" value=""><select id="dynamicmodel-selectname" class="form-select" name="DynamicModel[selectName]" size="4" placeholder>
<option value="1">One</option>
<option value="2">Two</option>
<option value="3">Three</option>
</select>
<label class="form-label" for="dynamicmodel-selectname">Select Name</label>
<div class="invalid-feedback"></div>
</div>
HTML;
$expected3 = <<<HTML
<div class="form-floating mt-3 field-dynamicmodel-checkboxname">
<div class="form-check">
<input type="hidden" name="DynamicModel[checkboxName]" value="0"><input type="checkbox" id="dynamicmodel-checkboxname" class="form-check-input" name="DynamicModel[checkboxName]" value="1">
<label class="form-check-label" for="dynamicmodel-checkboxname">Checkbox Name</label>
<div class="invalid-feedback"></div>
</div>
</div>
HTML;
$this->assertContainsWithoutLE('<form id="w0"', $out);
$this->assertContainsWithoutLE($expected, $out);
$this->assertContainsWithoutLE($expected2, $out);
$this->assertContainsWithoutLE($expected3, $out);
}
public function testHintRendering()
{
ActiveForm::$counter = 0;
ob_start();
$model = new User();
$form = ActiveForm::begin([
'action' => '/some-action',
'layout' => ActiveForm::LAYOUT_DEFAULT,
]);
echo $form->field($model, 'firstName');
echo $form->field($model, 'lastName');
echo $form->field($model, 'username');
echo $form->field($model, 'password')->passwordInput();
ActiveForm::end();
$out = ob_get_clean();
$expected = <<<HTML
<div class="mb-3 field-user-firstname">
<label class="form-label" for="user-firstname">First Name</label>
<input type="text" id="user-firstname" class="form-control" name="User[firstName]">
<div class="invalid-feedback"></div>
</div>
HTML;
$expected2 = <<<HTML
<div class="mb-3 field-user-lastname">
<label class="form-label" for="user-lastname">Last Name</label>
<input type="text" id="user-lastname" class="form-control" name="User[lastName]">
<div class="invalid-feedback"></div>
</div>
HTML;
$expected3 = <<<HTML
<div class="mb-3 field-user-username required">
<label class="form-label" for="user-username">Username</label>
<input type="text" id="user-username" class="form-control" name="User[username]" aria-required="true">
<div class="form-text text-muted">Your username must be at least 4 characters long</div>
<div class="invalid-feedback"></div>
</div>
HTML;
$expected4 = <<<HTML
<div class="mb-3 field-user-password required">
<label class="form-label" for="user-password">Password</label>
<input type="password" id="user-password" class="form-control" name="User[password]" aria-required="true">
<div class="form-text text-muted">Your password must be 8-20 characters long, contain letters and numbers, and must not contain spaces, special characters, or emoji.</div>
<div class="invalid-feedback"></div>
</div>
HTML;
$this->assertContainsWithoutLE($expected, $out);
$this->assertContainsWithoutLE($expected2, $out);
$this->assertContainsWithoutLE($expected3, $out);
$this->assertContainsWithoutLE($expected4, $out);
}
public function testStaticControlRendering()
{
ActiveForm::$counter = 0;
ob_start();
$model = new User();
$model->setAttributes([
'id' => 1,
'firstName' => 'John',
'lastName' => 'Doe',
]);
$form = ActiveForm::begin([
'action' => '/some-action',
'layout' => ActiveForm::LAYOUT_DEFAULT,
]);
echo $form->field($model, 'id')->staticControl();
echo $form->field($model, 'firstName')->staticControl();
echo $form->field($model, 'lastName')->staticControl();
echo $form->field($model, 'username')->staticControl();
ActiveForm::end();
$out = ob_get_clean();
$expected = <<<HTML
<div class="mb-3 field-user-id">
<label class="form-label" for="user-id">Id</label>
<input type="text" class="form-control-plaintext" value="1" readonly>
<div class="invalid-feedback"></div>
</div>
HTML;
$expected2 = <<<HTML
<div class="mb-3 field-user-firstname">
<label class="form-label" for="user-firstname">First Name</label>
<input type="text" class="form-control-plaintext" value="John" readonly>
<div class="invalid-feedback"></div>
</div>
HTML;
$expected3 = <<<HTML
<div class="mb-3 field-user-lastname">
<label class="form-label" for="user-lastname">Last Name</label>
<input type="text" class="form-control-plaintext" value="Doe" readonly>
<div class="invalid-feedback"></div>
</div>
HTML;
$this->assertContainsWithoutLE($expected, $out);
$this->assertContainsWithoutLE($expected2, $out);
$this->assertContainsWithoutLE($expected3, $out);
}
/**
* Fixes #128
* @see https://github.com/yiisoft/yii2-bootstrap5/issues/128
*/
public function testInputTemplate()
{
$model = new User();
$model->validate();
ActiveForm::$counter = 0;
ob_start();
$form = ActiveForm::begin();
echo $form->field($model, 'username', [
'inputTemplate' => '{input}',
]);
ActiveForm::end();
$out = ob_get_clean();
$expected = <<<HTML
<div class="mb-3 field-user-username required">
<label class="form-label" for="user-username">Username</label>
<input type="text" id="user-username" class="form-control is-invalid" name="User[username]" aria-required="true" aria-invalid="true">
<div class="form-text text-muted">Your username must be at least 4 characters long</div>
<div class="invalid-feedback">Username cannot be blank.</div>
</div>
HTML;
$this->assertContainsWithoutLE($expected, $out);
}
/**
* Fixes #196
*/
public function testFormNoRoleAttribute()
{
$form = ActiveForm::widget();
$this->assertStringNotContainsString('role="form"', $form);
}
public function testErrorSummaryRendering()
{
ActiveForm::$counter = 0;
ob_start();
$model = new User();
$model->validate();
$form = ActiveForm::begin([
'action' => '/some-action',
'layout' => ActiveForm::LAYOUT_DEFAULT,
]);
echo $form->errorSummary($model);
ActiveForm::end();
$out = ob_get_clean();
$this->assertContainsWithoutLE('<div class="alert alert-danger"', $out);
}
protected function setUp(): void
{
// dirty way to have Request object not throwing exception when running testFormNoRoleAttribute()
$_SERVER['REQUEST_URI'] = "index.php";
parent::setUp();
}
}

View File

@ -0,0 +1,92 @@
<?php
declare(strict_types=1);
namespace yiiunit\extensions\bootstrap5;
use yii\bootstrap5\Alert;
/**
* Tests for Alert widget
*
* @group bootstrap5
*/
class AlertTest extends TestCase
{
public function testNormalAlert()
{
Alert::$counter = 0;
$html = Alert::widget([
'body' => '<strong>Holy guacamole!</strong> You should check in on some of those fields below.',
'options' => [
'class' => ['alert-warning'],
],
]);
$expectedHtml = <<<HTML
<div id="w0" class="alert-warning alert alert-dismissible" role="alert">
<strong>Holy guacamole!</strong> You should check in on some of those fields below.
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
HTML;
$this->assertEqualsWithoutLE($expectedHtml, $html);
}
public function testDismissibleAlert()
{
Alert::$counter = 0;
$html = Alert::widget([
'body' => "Message1",
]);
$expectedHtml = <<<HTML
<div id="w0" class="alert alert-dismissible" role="alert">
Message1
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
HTML;
$this->assertEqualsWithoutLE($expectedHtml, $html);
}
/**
* @see https://github.com/yiisoft/yii2-bootstrap5/issues/11
*/
public function testDismissibleAlertCustomButton()
{
Alert::$counter = 0;
$html = Alert::widget([
'body' => "Low Blow: Bob Loblaw's Law Blog Lobs Law Bomb",
'options' => [
'class' => 'alert-warning',
],
'closeButton' => [
'label' => 'Dismiss',
'tag' => 'a',
'class' => [
'widget' => 'btn btn-outline-warning',
],
'style' => [
'position' => 'absolute',
'top' => '.5rem',
'right' => '.5rem',
],
],
]);
$expectedHtml = <<<HTML
<div id="w0" class="alert-warning alert alert-dismissible" role="alert">
Low Blow: Bob Loblaw's Law Blog Lobs Law Bomb
<a class="btn btn-outline-warning" data-bs-dismiss="alert" aria-label="Close" style="position: absolute; top: .5rem; right: .5rem;">Dismiss</a>
</div>
HTML;
$this->assertEqualsWithoutLE($expectedHtml, $html);
}
}

View File

@ -0,0 +1,66 @@
<?php
declare(strict_types=1);
namespace yiiunit\extensions\bootstrap5;
use yii\bootstrap5\Breadcrumbs;
/**
* @group bootstrap5
*/
class BreadcrumbsTest extends TestCase
{
public function testRender()
{
Breadcrumbs::$counter = 0;
$out = Breadcrumbs::widget([
'homeLink' => [
'label' => 'Home',
'url' => '#',
],
'links' => [
[
'label' => 'Library',
'url' => '#',
],
[
'label' => 'Data',
],
],
]);
$expected = <<<HTML
<nav aria-label="breadcrumb"><ol id="w0" class="breadcrumb"><li class="breadcrumb-item"><a href="#">Home</a></li>
<li class="breadcrumb-item"><a href="#">Library</a></li>
<li class="breadcrumb-item active" aria-current="page">Data</li>
</ol></nav>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testRenderWithoutHomeLink()
{
Breadcrumbs::$counter = 0;
$out = Breadcrumbs::widget([
'homeLink' => false,
'links' => [
[
'label' => 'Library',
'url' => '#',
],
[
'label' => 'Data',
],
],
]);
$expected = <<<HTML
<nav aria-label="breadcrumb"><ol id="w0" class="breadcrumb"><li class="breadcrumb-item"><a href="#">Library</a></li>
<li class="breadcrumb-item active" aria-current="page">Data</li>
</ol></nav>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
}

View File

@ -0,0 +1,132 @@
<?php
declare(strict_types=1);
namespace yiiunit\extensions\bootstrap5;
use yii\bootstrap5\ButtonDropdown;
/**
* @group bootstrap5
*/
class ButtonDropdownTest extends TestCase
{
public function testContainerOptions(): void
{
$containerClass = 'testClass';
ButtonDropdown::$counter = 0;
$out = ButtonDropdown::widget([
'direction' => ButtonDropdown::DIRECTION_UP,
'options' => [
'class' => $containerClass,
],
'label' => 'Action',
'dropdown' => [
'items' => [
[
'label' => 'DropdownA',
'url' => '/',
],
[
'label' => 'DropdownB',
'url' => '#',
],
],
],
]);
$this->assertStringContainsString("$containerClass dropup btn-group", $out);
}
public function testDirection(): void
{
ButtonDropdown::$counter = 0;
$out = ButtonDropdown::widget([
'direction' => ButtonDropdown::DIRECTION_LEFT,
'label' => 'Action',
'dropdown' => [
'items' => [
[
'label' => 'ItemA',
'url' => '#',
],
[
'label' => 'ItemB',
'url' => '#',
],
],
],
]);
$expected = <<<EXPECTED
<div id="w0" class="dropleft btn-group"><button id="w0-button" class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">Action</button>
<div id="w1" class="dropdown-menu"><a class="dropdown-item" href="#">ItemA</a>
<a class="dropdown-item" href="#">ItemB</a></div></div>
EXPECTED;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testSplit(): void
{
ButtonDropdown::$counter = 0;
$out = ButtonDropdown::widget([
'direction' => ButtonDropdown::DIRECTION_DOWN,
'label' => 'Split dropdown',
'split' => true,
'dropdown' => [
'items' => [
[
'label' => 'ItemA',
'url' => '#',
],
[
'label' => 'ItemB',
'url' => '#',
],
],
],
]);
$expected = <<<EXPECTED
<div id="w0" class="dropdown btn-group"><button id="w1" class="btn">Split dropdown</button>
<button id="w0-button" class="btn dropdown-toggle dropdown-toggle-split" data-bs-toggle="dropdown" aria-expanded="false"><span class="visually-hidden">Toggle Dropdown</span></button>
<div id="w2" class="dropdown-menu"><a class="dropdown-item" href="#">ItemA</a>
<a class="dropdown-item" href="#">ItemB</a></div></div>
EXPECTED;
$this->assertEqualsWithoutLE($expected, $out);
}
/**
* @see https://github.com/yiisoft/yii2-bootstrap5/pull/88 fix
*/
public function testGeneratedJS(): void
{
ButtonDropdown::$counter = 0;
$out = ButtonDropdown::widget([
'direction' => ButtonDropdown::DIRECTION_DOWN,
'label' => 'Action',
'dropdown' => [
'items' => [
[
'label' => 'DropdownA',
'url' => '/',
],
[
'label' => 'DropdownB',
'url' => '#',
],
],
],
]);
$js = array_shift(\Yii::$app->view->js);
$this->assertIsArray($js);
$this->assertNotContains('(new bootstrap.Button(\'#w0-button\', {}));', $js);
$this->assertContains('(new bootstrap.Dropdown(\'#w0-button\', {}));', $js);
}
}

View File

@ -0,0 +1,46 @@
<?php
declare(strict_types=1);
namespace yiiunit\extensions\bootstrap5;
use yii\bootstrap5\Button;
use yii\bootstrap5\ButtonGroup;
/**
* @group bootstrap5
*/
class ButtonGroupTest extends TestCase
{
public function testContainerOptions()
{
ButtonGroup::$counter = 0;
$out = ButtonGroup::widget([
'buttons' => [
[
'label' => 'button-A',
],
[
'label' => 'button-B',
'visible' => true,
],
[
'label' => 'button-C',
'visible' => false,
],
Button::widget([
'label' => 'button-D',
]),
],
]);
$expected = <<<HTML
<div id="w1" class="btn-group" role="group"><button type="button" id="w2" class="btn">button-A</button>
<button type="button" id="w3" class="btn">button-B</button>
<button id="w0" class="btn">button-D</button></div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
}

View File

@ -0,0 +1,130 @@
<?php
declare(strict_types=1);
namespace yiiunit\extensions\bootstrap5;
use yii\bootstrap5\ButtonGroup;
use yii\bootstrap5\ButtonToolbar;
/**
* @group bootstrap5
*/
class ButtonToolbarTest extends TestCase
{
public function testContainerOptions()
{
ButtonToolbar::$counter = 0;
$out = ButtonToolbar::widget([
'options' => [
'aria-label' => 'Toolbar with button groups',
],
'buttonGroups' => [
ButtonGroup::widget([
'options' => [
'aria-label' => 'First group',
'class' => ['mr-2'],
],
'buttons' => [
[
'label' => '1',
],
[
'label' => '2',
],
[
'label' => '3',
],
[
'label' => '4',
],
],
]),
[
'options' => [
'aria-label' => 'Second group',
],
'buttons' => [
[
'label' => '5',
],
[
'label' => '6',
],
[
'label' => '7',
],
],
],
],
]);
$expected = <<<HTML
<div id="w5" class="btn-toolbar" aria-label="Toolbar with button groups" role="toolbar"><div id="w0" class="mr-2 btn-group" aria-label="First group" role="group"><button type="button" id="w1" class="btn">1</button>
<button type="button" id="w2" class="btn">2</button>
<button type="button" id="w3" class="btn">3</button>
<button type="button" id="w4" class="btn">4</button></div>
<div id="w6" class="btn-group" aria-label="Second group" role="group"><button type="button" id="w7" class="btn">5</button>
<button type="button" id="w8" class="btn">6</button>
<button type="button" id="w9" class="btn">7</button></div></div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testAdditionalContent()
{
ButtonToolbar::$counter = 0;
$addHtml = <<<HTML
<div class="input-group">
<div class="input-group-prepend">
<div class="input-group-text" id="btnGroupAddon">@</div>
</div>
<input type="text" class="form-control" placeholder="Input group example" aria-label="Input group example" aria-describedby="btnGroupAddon">
</div>
HTML;
$out = ButtonToolbar::widget([
'options' => [
'aria-label' => 'Toolbar with button groups',
],
'buttonGroups' => [
[
'options' => [
'aria-label' => 'First group',
'class' => ['mr-2'],
],
'buttons' => [
[
'label' => '1',
],
[
'label' => '2',
],
[
'label' => '3',
],
[
'label' => '4',
],
],
],
$addHtml,
],
]);
$expected = <<<HTML
<div id="w0" class="btn-toolbar" aria-label="Toolbar with button groups" role="toolbar"><div id="w1" class="mr-2 btn-group" aria-label="First group" role="group"><button type="button" id="w2" class="btn">1</button>
<button type="button" id="w3" class="btn">2</button>
<button type="button" id="w4" class="btn">3</button>
<button type="button" id="w5" class="btn">4</button></div>
<div class="input-group">
<div class="input-group-prepend">
<div class="input-group-text" id="btnGroupAddon">@</div>
</div>
<input type="text" class="form-control" placeholder="Input group example" aria-label="Input group example" aria-describedby="btnGroupAddon">
</div></div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
}

View File

@ -0,0 +1,95 @@
<?php
declare(strict_types=1);
namespace yiiunit\extensions\bootstrap5;
use yii\bootstrap5\Carousel;
/**
* @group bootstrap5
*/
class CarouselTest extends TestCase
{
public function testContainerOptions()
{
Carousel::$counter = 0;
$out = Carousel::widget([
'items' => [
[
'content' => '<img src="https://via.placeholder.com/800x400?text=First+slide" class="d-block w-100">',
'caption' => '<h5>First slide label</h5><p>Nulla vitae elit libero, a pharetra augue mollis interdum.</p>',
'captionOptions' => [
'class' => ['d-none', 'd-md-block'],
],
],
[
'content' => '<img src="https://via.placeholder.com/800x400?text=Second+slide" class="d-block w-100">',
'caption' => '<h5>Second slide label</h5><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>',
'captionOptions' => [
'class' => ['d-none', 'd-md-block'],
],
],
[
'content' => '<img src="https://via.placeholder.com/800x400?text=Third+slide" class="d-block w-100">',
'caption' => '<h5>Third slide label</h5><p>Praesent commodo cursus magna, vel scelerisque nisl consectetur.</p>',
'captionOptions' => [
'class' => ['d-none', 'd-md-block'],
],
],
],
]);
$expected = <<<HTML
<div id="w0" class="carousel slide" data-bs-ride="carousel">
<div class="carousel-indicators"><button type="button" class="active" data-bs-target="#w0" data-bs-slide-to="0" aria-current="true"></button>
<button type="button" data-bs-target="#w0" data-bs-slide-to="1"></button>
<button type="button" data-bs-target="#w0" data-bs-slide-to="2"></button></div>
<div class="carousel-inner"><div class="carousel-item active"><img src="https://via.placeholder.com/800x400?text=First+slide" class="d-block w-100">
<div class="d-none d-md-block carousel-caption"><h5>First slide label</h5><p>Nulla vitae elit libero, a pharetra augue mollis interdum.</p></div></div>
<div class="carousel-item"><img src="https://via.placeholder.com/800x400?text=Second+slide" class="d-block w-100">
<div class="d-none d-md-block carousel-caption"><h5>Second slide label</h5><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p></div></div>
<div class="carousel-item"><img src="https://via.placeholder.com/800x400?text=Third+slide" class="d-block w-100">
<div class="d-none d-md-block carousel-caption"><h5>Third slide label</h5><p>Praesent commodo cursus magna, vel scelerisque nisl consectetur.</p></div></div></div>
<button type="button" class="carousel-control-prev" data-bs-target="#w0" data-bs-slide="prev"><span class="carousel-control-prev-icon" aria-hidden="true"></span><span class="visually-hidden">Previous</span></button>
<button type="button" class="carousel-control-next" data-bs-target="#w0" data-bs-slide="next"><span class="carousel-control-next-icon" aria-hidden="true"></span><span class="visually-hidden">Next</span></button>
</div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testCrossfade()
{
Carousel::$counter = 0;
$out = Carousel::widget([
'crossfade' => true,
'items' => [
[
'content' => '<img src="https://via.placeholder.com/800x400?text=First+slide" class="d-block w-100">',
'caption' => '<h5>First slide label</h5><p>Nulla vitae elit libero, a pharetra augue mollis interdum.</p>',
'captionOptions' => [
'class' => ['d-none', 'd-md-block'],
],
],
[
'content' => '<img src="https://via.placeholder.com/800x400?text=Second+slide" class="d-block w-100">',
'caption' => '<h5>Second slide label</h5><p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.</p>',
'captionOptions' => [
'class' => ['d-none', 'd-md-block'],
],
],
[
'content' => '<img src="https://via.placeholder.com/800x400?text=Third+slide" class="d-block w-100">',
'caption' => '<h5>Third slide label</h5><p>Praesent commodo cursus magna, vel scelerisque nisl consectetur.</p>',
'captionOptions' => [
'class' => ['d-none', 'd-md-block'],
],
],
],
]);
$this->assertStringContainsString('class="carousel slide carousel-fade"', $out);
}
}

View File

@ -0,0 +1,305 @@
<?php
declare(strict_types=1);
namespace yiiunit\extensions\bootstrap5;
use yii\bootstrap5\Dropdown;
/**
* Tests for Dropdown widget
*
* @group bootstrap5
*/
class DropdownTest extends TestCase
{
public function testIds()
{
Dropdown::$counter = 0;
$out = Dropdown::widget(
[
'items' => [
[
'label' => 'Page1',
],
[
'label' => 'Dropdown1',
'url' => '#test',
'items' => [
[
'label' => 'Page2',
],
[
'label' => 'Page3',
],
],
],
[
'label' => 'Dropdown2',
'visible' => false,
'items' => [
[
'label' => 'Page4',
'content' => 'Page4',
],
[
'label' => 'Page5',
'content' => 'Page5',
],
],
],
],
],
);
$expected = <<<EXPECTED
<div id="w0" class="dropdown-menu"><h6 class="dropdown-header">Page1</h6>
<div class="dropdown" aria-expanded="false">
<a class="dropdown-item dropdown-toggle" href="#test" data-bs-toggle="dropdown" aria-expanded="false" role="button">Dropdown1</a>
<div id="w1" class="dropdown-submenu dropdown-menu"><h6 class="dropdown-header">Page2</h6>
<h6 class="dropdown-header">Page3</h6></div>
</div></div>
EXPECTED;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testSubMenuOptions()
{
Dropdown::$counter = 0;
$out = Dropdown::widget(
[
'submenuOptions' => [
'class' => 'submenu-list',
],
'items' => [
[
'label' => 'Dropdown1',
'items' => [
[
'label' => 'Page1',
'content' => 'Page2',
],
[
'label' => 'Page2',
'content' => 'Page3',
],
],
],
'-',
[
'label' => 'Dropdown2',
'items' => [
[
'label' => 'Page3',
'content' => 'Page4',
],
[
'label' => 'Page4',
'content' => 'Page5',
],
],
'submenuOptions' => [
'class' => 'submenu-override',
],
],
],
],
);
$expected = <<<EXPECTED
<div id="w0" class="dropdown-menu"><div class="dropdown" aria-expanded="false">
<a class="dropdown-item dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false" role="button">Dropdown1</a>
<div id="w1" class="submenu-list dropdown-submenu dropdown-menu"><h6 class="dropdown-header">Page1</h6>
<h6 class="dropdown-header">Page2</h6></div>
</div>
<hr class="dropdown-divider">
<div class="dropdown" aria-expanded="false">
<a class="dropdown-item dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false" role="button">Dropdown2</a>
<div id="w2" class="submenu-override dropdown-submenu dropdown-menu"><h6 class="dropdown-header">Page3</h6>
<h6 class="dropdown-header">Page4</h6></div>
</div></div>
EXPECTED;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testActive()
{
Dropdown::$counter = 0;
$out = Dropdown::widget(
[
'submenuOptions' => [
'class' => 'submenu-list',
],
'items' => [
[
'label' => 'Dropdown1',
'items' => [
[
'label' => 'Page1',
'content' => 'Page2',
],
[
'label' => 'Page2',
'content' => 'Page3',
],
],
],
'-',
[
'label' => 'Dropdown2',
'items' => [
[
'label' => 'Page3',
'content' => 'Page3',
'url' => '/',
'active' => true,
],
[
'label' => 'Page4',
'content' => 'Page4',
],
],
],
],
],
);
$expected = <<<HTML
<div id="w0" class="dropdown-menu"><div class="dropdown" aria-expanded="false">
<a class="dropdown-item dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false" role="button">Dropdown1</a>
<div id="w1" class="submenu-list dropdown-submenu dropdown-menu"><h6 class="dropdown-header">Page1</h6>
<h6 class="dropdown-header">Page2</h6></div>
</div>
<hr class="dropdown-divider">
<div class="dropdown" aria-expanded="false">
<a class="dropdown-item dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false" role="button">Dropdown2</a>
<div id="w2" class="submenu-list dropdown-submenu dropdown-menu"><a class="dropdown-item active" href="/" aria-current="true">Page3</a>
<h6 class="dropdown-header">Page4</h6></div>
</div></div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testDisabled()
{
Dropdown::$counter = 0;
$out = Dropdown::widget(
[
'submenuOptions' => [
'class' => 'submenu-list',
],
'items' => [
[
'label' => 'Dropdown1',
'items' => [
[
'label' => 'Page1',
'content' => 'Page2',
],
[
'label' => 'Page2',
'content' => 'Page3',
],
],
'disabled' => true,
],
'-',
[
'label' => 'Dropdown2',
'items' => [
[
'label' => 'Page3',
'content' => 'Page3',
],
[
'label' => 'Page4',
'content' => 'Page4',
],
],
],
],
],
);
$expected = <<<HTML
<div id="w0" class="dropdown-menu"><div class="dropdown" aria-expanded="false">
<a class="dropdown-item disabled dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false" aria-disabled="true" role="button" tabindex="-1">Dropdown1</a>
<div id="w1" class="submenu-list dropdown-submenu dropdown-menu"><h6 class="dropdown-header">Page1</h6>
<h6 class="dropdown-header">Page2</h6></div>
</div>
<hr class="dropdown-divider">
<div class="dropdown" aria-expanded="false">
<a class="dropdown-item dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false" role="button">Dropdown2</a>
<div id="w2" class="submenu-list dropdown-submenu dropdown-menu"><h6 class="dropdown-header">Page3</h6>
<h6 class="dropdown-header">Page4</h6></div>
</div></div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testForms()
{
Dropdown::$counter = 0;
$form = <<<HTML
<form class="px-4 py-3">
<div class="mb-3">
<label class="form-label" for="exampleDropdownFormEmail1">Email address</label>
<input type="email" class="form-control" id="exampleDropdownFormEmail1" placeholder="email@example.com">
</div>
<div class="mb-3">
<label class="form-label" for="exampleDropdownFormPassword1">Password</label>
<input type="password" class="form-control" id="exampleDropdownFormPassword1" placeholder="Password">
</div>
<div class="form-check">
<input type="checkbox" class="form-check-input" id="dropdownCheck">
<label class="form-check-label" for="dropdownCheck">
Remember me
</label>
</div>
<button type="submit" class="btn btn-primary">Sign in</button>
</form>
HTML;
$out = Dropdown::widget([
'items' => [
$form,
'-',
[
'label' => 'New around here? Sign up',
'url' => '#',
],
[
'label' => 'Forgot password?',
'url' => '#',
],
],
]);
$expected = <<<HTML
<div id="w0" class="dropdown-menu"><form class="px-4 py-3">
<div class="mb-3">
<label class="form-label" for="exampleDropdownFormEmail1">Email address</label>
<input type="email" class="form-control" id="exampleDropdownFormEmail1" placeholder="email@example.com">
</div>
<div class="mb-3">
<label class="form-label" for="exampleDropdownFormPassword1">Password</label>
<input type="password" class="form-control" id="exampleDropdownFormPassword1" placeholder="Password">
</div>
<div class="form-check">
<input type="checkbox" class="form-check-input" id="dropdownCheck">
<label class="form-check-label" for="dropdownCheck">
Remember me
</label>
</div>
<button type="submit" class="btn btn-primary">Sign in</button>
</form>
<hr class="dropdown-divider">
<a class="dropdown-item" href="#">New around here? Sign up</a>
<a class="dropdown-item" href="#">Forgot password?</a></div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
}

View File

@ -0,0 +1,168 @@
<?php
declare(strict_types=1);
namespace yiiunit\extensions\bootstrap5;
use yii\base\DynamicModel;
use yii\bootstrap5\Html;
/**
* @group bootstrap5
*/
class HtmlTest extends TestCase
{
/**
* @return array
*/
public function dataProviderStaticControl()
{
return [
[
'foo',
[],
'<input type="text" class="form-control-plaintext" value="foo" readonly>',
],
[
'<html>',
[],
'<input type="text" class="form-control-plaintext" value="&lt;html&gt;" readonly>',
],
];
}
/**
* @dataProvider dataProviderStaticControl
*
* @param string $value
* @param string $expectedHtml
*/
public function testStaticControl($value, array $options, $expectedHtml)
{
$this->assertEquals($expectedHtml, Html::staticControl($value, $options));
}
public function testRadioList()
{
$this->assertEquals('<div></div>', Html::radioList('test'));
$dataItems = [
'value1' => 'text1',
'value2' => 'text2',
];
Html::$counter = 0;
$expected = <<<'EOD'
<div><div class="form-check"><input type="radio" id="i0" class="form-check-input" name="test" value="value1">
<label class="form-check-label" for="i0">text1</label></div>
<div class="form-check"><input type="radio" id="i1" class="form-check-input" name="test" value="value2" checked>
<label class="form-check-label" for="i1">text2</label></div></div>
EOD;
$this->assertEqualsWithoutLE($expected, Html::radioList('test', ['value2'], $dataItems));
Html::$counter = 0;
$expected = <<<'EOD'
<div>0<label>text1 <input type="radio" name="test" value="value1"></label>
1<label>text2 <input type="radio" name="test" value="value2" checked></label></div>
EOD;
$this->assertEqualsWithoutLE($expected, Html::radioList('test', ['value2'], $dataItems, [
'item' => function ($index, $label, $name, $checked, $value) {
return $index . Html::label($label . ' ' . Html::radio($name, $checked, [
'value' => $value,
]));
},
]));
Html::$counter = 0;
$expected = <<<'EOD'
<div><div class="form-check"><input type="radio" id="i0" class="form-check-input" name="test" value="value">
<label class="form-check-label" for="i0">label&amp;</label></div></div>
EOD;
$this->assertEqualsWithoutLE($expected, Html::radioList('test', [], [
'value' => 'label&',
]));
Html::$counter = 0;
$expected = <<<'EOD'
<div><div class="form-check"><input type="radio" id="i0" class="form-check-input" name="test" value="value">
<label class="form-check-label" for="i0">label&</label></div></div>
EOD;
$this->assertEqualsWithoutLE($expected, Html::radioList('test', [], [
'value' => 'label&',
], [
'encode' => false,
]));
}
public function testCheckboxList()
{
$this->assertEquals('<div></div>', Html::checkboxList('test'));
$dataItems = [
'value1' => 'text1',
'value2' => 'text2',
];
Html::$counter = 0;
$expected = <<<'EOD'
<div><div class="form-check"><input type="checkbox" id="i0" class="form-check-input" name="test[]" value="value1">
<label class="form-check-label" for="i0">text1</label></div>
<div class="form-check"><input type="checkbox" id="i1" class="form-check-input" name="test[]" value="value2" checked>
<label class="form-check-label" for="i1">text2</label></div></div>
EOD;
$this->assertEqualsWithoutLE($expected, Html::checkboxList('test', ['value2'], $dataItems));
Html::$counter = 0;
$expected = <<<'EOD'
<div>0<label>text1 <input type="checkbox" name="test[]" value="value1"></label>
1<label>text2 <input type="checkbox" name="test[]" value="value2" checked></label></div>
EOD;
$this->assertEqualsWithoutLE($expected, Html::checkboxList('test', ['value2'], $dataItems, [
'item' => function ($index, $label, $name, $checked, $value) {
return $index . Html::label($label . ' ' . Html::checkbox($name, $checked, [
'value' => $value,
]));
},
]));
Html::$counter = 0;
$expected = <<<'EOD'
<div><div class="form-check"><input type="checkbox" id="i0" class="form-check-input" name="test[]" value="value" checked>
<label class="form-check-label" for="i0">label&amp;</label></div></div>
EOD;
$this->assertEqualsWithoutLE($expected, Html::checkboxList('test', 'value', [
'value' => 'label&',
]));
Html::$counter = 0;
$expected = <<<'EOD'
<div><div class="form-check"><input type="checkbox" id="i0" class="form-check-input" name="test[]" value="value" checked>
<label class="form-check-label" for="i0">label&</label></div></div>
EOD;
$this->assertEqualsWithoutLE($expected, Html::checkboxList('test', 'value', [
'value' => 'label&',
], [
'encode' => false,
]));
}
public function testError()
{
$model = new DynamicModel();
$model->addError('foo', 'Some error message.');
$this->assertEquals('<div class="invalid-feedback">Some error message.</div>', Html::error($model, 'foo'));
$this->assertEquals('<div class="custom-class">Some error message.</div>', Html::error($model, 'foo', [
'class' => 'custom-class',
]));
$this->assertEquals('<div>Some error message.</div>', Html::error($model, 'foo', [
'class' => null,
]));
$this->assertEquals('<p class="invalid-feedback">Some error message.</p>', Html::error($model, 'foo', [
'tag' => 'p',
]));
}
}

View File

@ -0,0 +1,252 @@
<?php
declare(strict_types=1);
/**
* @link https://www.yiiframework.com/
* @copyright Copyright (c) 2008 Yii Software LLC
* @license https://www.yiiframework.com/license/
*/
namespace yiiunit\extensions\bootstrap5;
use yii\bootstrap5\LinkPager;
use yii\data\Pagination;
use yii\helpers\ReplaceArrayValue;
use yii\helpers\StringHelper;
/**
* @group bootstrap5
*/
class LinkPagerTest extends TestCase
{
public function testFirstLastPageLabels()
{
$pagination = $this->getPagination(5);
$output = LinkPager::widget([
'pagination' => $pagination,
'firstPageLabel' => true,
'lastPageLabel' => true,
]);
$this->assertStringContainsString('<li class="page-item first"><a class="page-link" href="/?r=test&amp;page=1" data-page="0">1</a></li>', $output);
$this->assertStringContainsString('<li class="page-item last"><a class="page-link" href="/?r=test&amp;page=25" data-page="24">25</a></li>', $output);
$output = LinkPager::widget([
'pagination' => $pagination,
'firstPageLabel' => 'First',
'lastPageLabel' => 'Last',
]);
$this->assertStringContainsString('<li class="page-item first"><a class="page-link" href="/?r=test&amp;page=1" data-page="0">First</a></li>', $output);
$this->assertStringContainsString('<li class="page-item last"><a class="page-link" href="/?r=test&amp;page=25" data-page="24">Last</a></li>', $output);
$output = LinkPager::widget([
'pagination' => $pagination,
'firstPageLabel' => false,
'lastPageLabel' => false,
]);
$this->assertStringNotContainsString('<li class="page-item first">', $output);
$this->assertStringNotContainsString('<li class="page-item last">', $output);
}
public function testDisabledPageElementOptions()
{
$output = LinkPager::widget([
'pagination' => $this->getPagination(0),
'disabledListItemSubTagOptions' => [
'class' => ['foo-bar'],
],
]);
$this->assertStringContainsString('<li class="page-item prev disabled"><a class="page-link foo-bar"', $output);
}
public function testOverrideDisabledPageElementOptions()
{
$output = LinkPager::widget([
'pagination' => $this->getPagination(0),
'disabledListItemSubTagOptions' => [
'class' => new ReplaceArrayValue(['foo-bar']),
],
]);
$this->assertStringContainsString('<li class="page-item prev disabled"><a class="foo-bar"', $output);
}
public function testDisableCurrentPageButton()
{
$pagination = $this->getPagination(5);
$output = LinkPager::widget([
'pagination' => $pagination,
'disableCurrentPageButton' => false,
]);
$this->assertStringContainsString('<li class="page-item active" aria-current="page"><a class="page-link" href="/?r=test&amp;page=6" data-page="5">6</a></li>', $output);
$output = LinkPager::widget([
'pagination' => $pagination,
'disableCurrentPageButton' => true,
]);
$this->assertStringContainsString('<li class="page-item active disabled" aria-current="page"><a class="page-link" href="/?r=test&amp;page=6" data-page="5" tabindex="-1">6</a></li>', $output);
}
public function testOptionsWithTagOption()
{
LinkPager::$counter = 0;
$output = LinkPager::widget([
'pagination' => $this->getPagination(5),
'options' => [
'tag' => 'div',
],
]);
$this->assertTrue(StringHelper::startsWith($output, '<div id="w0">'));
$this->assertTrue(StringHelper::endsWith($output, '</div>'));
}
public function testLinkWrapOptions()
{
$output = LinkPager::widget([
'pagination' => $this->getPagination(1),
'linkContainerOptions' => [
'tag' => 'div',
'class' => 'my-class',
],
]);
$this->assertStringContainsString(
'<div class="my-class page-item"><a class="page-link" href="/?r=test&amp;page=3" data-page="2">3</a></div>',
$output,
);
$this->assertStringContainsString(
'<div class="my-class page-item active" aria-current="page"><a class="page-link" href="/?r=test&amp;page=2" data-page="1">2</a></div>',
$output,
);
}
public function testWithTwoButtons()
{
$output = LinkPager::widget([
'pagination' => $this->getPagination(0),
'maxButtonCount' => 2,
]);
$this->assertContainsWithoutLE(
<<<HTML
<ul class="pagination"><li class="page-item prev disabled"><a class="page-link" href="/?r=test&amp;page=1" data-page="0" tabindex="-1"><span aria-hidden="true">&laquo;</span></a></li>
<li class="page-item active" aria-current="page"><a class="page-link" href="/?r=test&amp;page=1" data-page="0">1</a></li>
<li class="page-item"><a class="page-link" href="/?r=test&amp;page=2" data-page="1">2</a></li>
<li class="page-item next"><a class="page-link" href="/?r=test&amp;page=2" data-page="1"><span aria-hidden="true">&raquo;</span></a></li></ul>
HTML,
$output,
);
$output = LinkPager::widget([
'pagination' => $this->getPagination(1),
'maxButtonCount' => 2,
]);
$this->assertContainsWithoutLE(
<<<HTML
<ul class="pagination"><li class="page-item prev"><a class="page-link" href="/?r=test&amp;page=1" data-page="0"><span aria-hidden="true">&laquo;</span></a></li>
<li class="page-item active" aria-current="page"><a class="page-link" href="/?r=test&amp;page=2" data-page="1">2</a></li>
<li class="page-item"><a class="page-link" href="/?r=test&amp;page=3" data-page="2">3</a></li>
<li class="page-item next"><a class="page-link" href="/?r=test&amp;page=3" data-page="2"><span aria-hidden="true">&raquo;</span></a></li></ul>
HTML,
$output,
);
}
public function testWithOneButton()
{
$output = LinkPager::widget([
'pagination' => $this->getPagination(0),
'maxButtonCount' => 1,
]);
$this->assertContainsWithoutLE(
<<<HTML
<ul class="pagination"><li class="page-item prev disabled"><a class="page-link" href="/?r=test&amp;page=1" data-page="0" tabindex="-1"><span aria-hidden="true">&laquo;</span></a></li>
<li class="page-item active" aria-current="page"><a class="page-link" href="/?r=test&amp;page=1" data-page="0">1</a></li>
<li class="page-item next"><a class="page-link" href="/?r=test&amp;page=2" data-page="1"><span aria-hidden="true">&raquo;</span></a></li></ul>
HTML,
$output,
);
$output = LinkPager::widget([
'pagination' => $this->getPagination(1),
'maxButtonCount' => 1,
]);
$this->assertContainsWithoutLE(
<<<HTML
<ul class="pagination"><li class="page-item prev"><a class="page-link" href="/?r=test&amp;page=1" data-page="0"><span aria-hidden="true">&laquo;</span></a></li>
<li class="page-item active" aria-current="page"><a class="page-link" href="/?r=test&amp;page=2" data-page="1">2</a></li>
<li class="page-item next"><a class="page-link" href="/?r=test&amp;page=3" data-page="2"><span aria-hidden="true">&raquo;</span></a></li></ul>
HTML,
$output,
);
}
public function testWithNoButtons()
{
$output = LinkPager::widget([
'pagination' => $this->getPagination(0),
'maxButtonCount' => 0,
]);
$this->assertContainsWithoutLE(
<<<HTML
<ul class="pagination"><li class="page-item prev disabled"><a class="page-link" href="/?r=test&amp;page=1" data-page="0" tabindex="-1"><span aria-hidden="true">&laquo;</span></a></li>
<li class="page-item next"><a class="page-link" href="/?r=test&amp;page=2" data-page="1"><span aria-hidden="true">&raquo;</span></a></li></ul>
HTML,
$output,
);
$output = LinkPager::widget([
'pagination' => $this->getPagination(1),
'maxButtonCount' => 0,
]);
$this->assertContainsWithoutLE(
<<<HTML
<ul class="pagination"><li class="page-item prev"><a class="page-link" href="/?r=test&amp;page=1" data-page="0"><span aria-hidden="true">&laquo;</span></a></li>
<li class="page-item next"><a class="page-link" href="/?r=test&amp;page=3" data-page="2"><span aria-hidden="true">&raquo;</span></a></li></ul>
HTML,
$output,
);
}
/**
* @see https://github.com/yiisoft/yii2/issues/15536
*/
public function testShouldTriggerInitEvent()
{
$initTriggered = false;
LinkPager::widget([
'pagination' => $this->getPagination(1),
'on init' => function () use (&$initTriggered) {
$initTriggered = true;
},
]);
$this->assertTrue($initTriggered);
}
protected function setUp(): void
{
parent::setUp();
$this->mockWebApplication([
'components' => [
'urlManager' => [
'scriptUrl' => '/',
],
],
]);
}
/**
* Get pagination.
* @param int $page
* @return Pagination
*/
private function getPagination($page)
{
$pagination = new Pagination();
$pagination->setPage($page);
$pagination->totalCount = 500;
$pagination->route = 'test';
return $pagination;
}
}

View File

@ -0,0 +1,204 @@
<?php
declare(strict_types=1);
namespace yiiunit\extensions\bootstrap5;
use yii\bootstrap5\Html;
use yii\bootstrap5\Modal;
/**
* @group bootstrap5
*/
class ModalTest extends TestCase
{
public function testBodyOptions()
{
Modal::$counter = 0;
$out = Modal::widget([
'closeButton' => false,
'bodyOptions' => [
'class' => 'modal-body test',
'style' => 'text-align:center;',
],
]);
$expected = <<<HTML
<div id="w0" class="modal fade" tabindex="-1" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-body test" style="text-align:center;">
</div>
</div>
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testContainerOptions()
{
Modal::$counter = 0;
ob_start();
Modal::begin([
'title' => 'Modal title',
'footer' => Html::button('Close', [
'type' => 'button',
'class' => ['btn', 'btn-secondary'],
'data' => [
'bs-dismiss' => 'modal',
],
]) . "\n" . Html::button('Save changes', [
'type' => 'button',
'class' => ['btn', 'btn-primary'],
]),
]);
echo '<p>Woohoo, you\'re reading this text in a modal!</p>';
Modal::end();
$out = ob_get_clean();
$expected = <<<HTML
<div id="w0" class="modal fade" tabindex="-1" aria-hidden="true" aria-labelledby="w0-label">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 id="w0-label" class="modal-title">Modal title</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<p>Woohoo, you're reading this text in a modal!</p>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
<button type="button" class="btn btn-primary">Save changes</button>
</div>
</div>
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testTriggerButton()
{
Modal::$counter = 0;
ob_start();
Modal::begin([
'toggleButton' => [
'class' => ['btn', 'btn-primary'],
'label' => 'Launch demo modal',
],
'title' => 'Modal title',
'footer' => Html::button('Close', [
'type' => 'button',
'class' => ['btn', 'btn-secondary'],
]) . "\n" . Html::button('Save changes', [
'type' => 'button',
'class' => ['btn', 'btn-primary'],
]),
]);
echo '<p>Woohoo, you\'re reading this text in a modal!</p>';
Modal::end();
$out = ob_get_clean();
$this->assertStringContainsString(
'<button type="button" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#w0">Launch demo modal</button>',
$out,
);
}
public function testDialogOptions()
{
Modal::$counter = 0;
$out = Modal::widget([
'closeButton' => false,
'dialogOptions' => [
'class' => 'test',
'style' => 'text-align:center;',
],
]);
$expected = <<<HTML
<div id="w0" class="modal fade" tabindex="-1" aria-hidden="true">
<div class="test modal-dialog" style="text-align:center;">
<div class="modal-content">
<div class="modal-body">
</div>
</div>
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testCenterVertical()
{
Modal::$counter = 0;
$out = Modal::widget([
'closeButton' => false,
'centerVertical' => true,
]);
$expected = <<<HTML
<div id="w0" class="modal fade" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-content">
<div class="modal-body">
</div>
</div>
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testScrollable()
{
Modal::$counter = 0;
$out = Modal::widget([
'closeButton' => false,
'scrollable' => true,
]);
$expected = <<<HTML
<div id="w0" class="modal fade" tabindex="-1" aria-hidden="true">
<div class="modal-dialog modal-dialog-scrollable">
<div class="modal-content">
<div class="modal-body">
</div>
</div>
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
}

View File

@ -0,0 +1,267 @@
<?php
declare(strict_types=1);
namespace yiiunit\extensions\bootstrap5;
use yii\bootstrap5\Nav;
use yii\bootstrap5\NavBar;
use yii\bootstrap5\Offcanvas;
/**
* Tests for NavBar widget
*
* @group bootstrap5
*/
class NavBarTest extends TestCase
{
public function testRender()
{
NavBar::$counter = 0;
$out = NavBar::widget([
'brandLabel' => 'My Company',
'brandUrl' => '/',
'options' => [
'class' => 'navbar-inverse navbar-static-top navbar-frontend',
],
]);
$expected = <<<EXPECTED
<nav id="w0" class="navbar-inverse navbar-static-top navbar-frontend navbar">
<div class="container">
<a class="navbar-brand" href="/">My Company</a>
<button type="button" class="navbar-toggler" data-bs-toggle="collapse" data-bs-target="#w0-collapse" aria-controls="w0-collapse" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button>
<div id="w0-collapse" class="collapse navbar-collapse">
</div>
</div>
</nav>
EXPECTED;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testBrandImage()
{
$out = NavBar::widget([
'brandImage' => '/images/test.jpg',
'brandUrl' => '/',
]);
$this->assertStringContainsString('<a class="navbar-brand" href="/"><img src="/images/test.jpg" alt=""></a>', $out);
}
public function testBrandImageOptions()
{
$out = NavBar::widget([
'brandImage' => '/images/test.jpg',
'brandImageOptions' => [
'alt' => 'test image',
],
'brandUrl' => '/',
]);
$this->assertStringContainsString('<a class="navbar-brand" href="/"><img src="/images/test.jpg" alt="test image"></a>', $out);
}
public function testBrandLink()
{
$out = NavBar::widget([
'brandLabel' => 'Yii Framework',
'brandUrl' => false,
]);
$this->assertStringContainsString('<a class="navbar-brand" href="/index.php">Yii Framework</a>', $out);
}
public function testBrandSpan()
{
$out = NavBar::widget([
'brandLabel' => 'Yii Framework',
'brandUrl' => null,
]);
$this->assertStringContainsString('<span class="navbar-brand">Yii Framework</span>', $out);
}
public function testNavAndForm()
{
NavBar::$counter = 0;
ob_start();
NavBar::begin([
'brandLabel' => 'My Company',
'brandUrl' => '/',
'options' => [
],
]);
echo Nav::widget([
'options' => [
'class' => ['mr-auto'],
],
'items' => [
[
'label' => 'Home',
'url' => '#',
],
[
'label' => 'Link',
'url' => '#',
],
[
'label' => 'Dropdown',
'items' => [
[
'label' => 'Action',
'url' => '#',
],
[
'label' => 'Another action',
'url' => '#',
],
'-',
[
'label' => 'Something else here',
'url' => '#',
],
],
],
],
]);
echo <<<HTML
<form class="form-inline my-2 my-lg-0">
<input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search">
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
</form>
HTML;
NavBar::end();
$out = ob_get_clean();
$expected = <<<EXPECTED
<nav id="w0" class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container">
<a class="navbar-brand" href="/">My Company</a>
<button type="button" class="navbar-toggler" data-bs-toggle="collapse" data-bs-target="#w0-collapse" aria-controls="w0-collapse" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button>
<div id="w0-collapse" class="collapse navbar-collapse">
<ul id="w1" class="mr-auto nav"><li class="nav-item"><a class="nav-link" href="#">Home</a></li>
<li class="nav-item"><a class="nav-link" href="#">Link</a></li>
<li class="dropdown nav-item"><a class="dropdown-toggle nav-link" href="#" data-bs-toggle="dropdown" role="button" aria-expanded="false">Dropdown</a><div id="w2" class="dropdown-menu"><a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<hr class="dropdown-divider">
<a class="dropdown-item" href="#">Something else here</a></div></li></ul><form class="form-inline my-2 my-lg-0">
<input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search">
<button class="btn btn-outline-success my-2 my-sm-0" type="submit">Search</button>
</form></div>
</div>
</nav>
EXPECTED;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testOffcanvasNavigation()
{
NavBar::$counter = 0;
ob_start();
NavBar::begin([
'brandLabel' => 'Offcanvas navbar',
'brandUrl' => ['/'],
'options' => [
'class' => ['navbar', 'navbar-light', 'bg-light', 'fixed-top'],
],
'innerContainerOptions' => [
'class' => ['container-fluid'],
],
'collapseOptions' => false,
'offcanvasOptions' => [
'title' => 'Offcanvas',
'placement' => Offcanvas::PLACEMENT_END,
],
]);
echo Nav::widget([
'options' => [
'class' => ['navbar-nav'],
],
'items' => [
[
'label' => 'Home',
'url' => '#',
],
[
'label' => 'Link',
'url' => '#',
],
[
'label' => 'Dropdown',
'items' => [
[
'label' => 'Action',
'url' => '#',
],
[
'label' => 'Another action',
'url' => '#',
],
'-',
[
'label' => 'Something else here',
'url' => '#',
],
],
],
],
]);
NavBar::end();
$out = ob_get_clean();
$expected = <<<HTML
<nav id="w0" class="navbar navbar-light bg-light fixed-top">
<div class="container-fluid">
<a class="navbar-brand" href="/index.php?r=">Offcanvas navbar</a>
<button type="button" class="navbar-toggler" data-bs-toggle="offcanvas" data-bs-target="#w0-offcanvas" aria-controls="w0-offcanvas" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button>
<div id="w0-offcanvas" class="offcanvas offcanvas-end" tabindex="-1" data-bs-backdrop="true" data-bs-scroll="false" aria-labelledby="w0-offcanvas-label">
<div class="offcanvas-header">
<h5 id="w0-offcanvas-label" class="offcanvas-title">Offcanvas</h5>
<button type="button" class="btn-close text-reset" data-bs-dismiss="offcanvas" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
<ul id="w1" class="navbar-nav nav"><li class="nav-item"><a class="nav-link" href="#">Home</a></li>
<li class="nav-item"><a class="nav-link" href="#">Link</a></li>
<li class="dropdown nav-item"><a class="dropdown-toggle nav-link" href="#" data-bs-toggle="dropdown" role="button" aria-expanded="false">Dropdown</a><div id="w2" class="dropdown-menu"><a class="dropdown-item" href="#">Action</a>
<a class="dropdown-item" href="#">Another action</a>
<hr class="dropdown-divider">
<a class="dropdown-item" href="#">Something else here</a></div></li></ul>
</div>
</div></div>
</nav>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testNoCollapse()
{
NavBar::$counter = 0;
$out = NavBar::widget([
'brandLabel' => 'My Company',
'brandUrl' => '/',
'collapseOptions' => false,
]);
$expected = <<<EXPECTED
<nav id="w0" class="navbar navbar-expand-lg navbar-light bg-light">
<div class="container">
<a class="navbar-brand" href="/">My Company</a>
</div>
</nav>
EXPECTED;
$this->assertEqualsWithoutLE($expected, $out);
}
}

View File

@ -0,0 +1,443 @@
<?php
declare(strict_types=1);
namespace yiiunit\extensions\bootstrap5;
use yii\bootstrap5\Nav;
/**
* Tests for Nav widget
*
* @group bootstrap5
*/
class NavTest extends TestCase
{
public function testIds()
{
Nav::$counter = 0;
$out = Nav::widget(
[
'items' => [
[
'label' => 'Page1',
'content' => 'Page1',
],
[
'label' => 'Dropdown1',
'items' => [
[
'label' => 'Page2',
'content' => 'Page2',
],
[
'label' => 'Page3',
'content' => 'Page3',
],
],
],
[
'label' => 'Dropdown2',
'visible' => false,
'items' => [
[
'label' => 'Page4',
'content' => 'Page4',
],
[
'label' => 'Page5',
'content' => 'Page5',
],
],
],
],
],
);
$expected = <<<EXPECTED
<ul id="w0" class="nav"><li class="nav-item"><a class="nav-link" href="#">Page1</a></li>
<li class="dropdown nav-item"><a class="dropdown-toggle nav-link" href="#" data-bs-toggle="dropdown" role="button" aria-expanded="false">Dropdown1</a><div id="w1" class="dropdown-menu"><h6 class="dropdown-header">Page2</h6>
<h6 class="dropdown-header">Page3</h6></div></li></ul>
EXPECTED;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testRenderDropdownWithDropdownOptions()
{
Nav::$counter = 0;
$out = Nav::widget(
[
'items' => [
[
'label' => 'Page1',
'content' => 'Page1',
],
[
'label' => 'Dropdown1',
'dropdownOptions' => [
'class' => 'test',
'data-id' => 't1',
'id' => 'test1',
],
'items' => [
[
'label' => 'Page2',
'content' => 'Page2',
],
[
'label' => 'Page3',
'content' => 'Page3',
],
],
],
[
'label' => 'Dropdown2',
'visible' => false,
'items' => [
[
'label' => 'Page4',
'content' => 'Page4',
],
[
'label' => 'Page5',
'content' => 'Page5',
],
],
],
],
],
);
$expected = <<<EXPECTED
<ul id="w0" class="nav"><li class="nav-item"><a class="nav-link" href="#">Page1</a></li>
<li class="dropdown nav-item"><a class="dropdown-toggle nav-link" href="#" data-bs-toggle="dropdown" role="button" aria-expanded="false">Dropdown1</a><div id="test1" class="test dropdown-menu" data-id="t1"><h6 class="dropdown-header">Page2</h6>
<h6 class="dropdown-header">Page3</h6></div></li></ul>
EXPECTED;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testEmptyItems()
{
Nav::$counter = 0;
$out = Nav::widget([
'items' => [
[
'label' => 'Page1',
'items' => null,
],
[
'label' => 'Dropdown1',
'items' => [
[
'label' => 'Page2',
'content' => 'Page2',
],
[
'label' => 'Page3',
'content' => 'Page3',
],
],
],
[
'label' => 'Page4',
'items' => [],
],
],
]);
$expected = <<<EXPECTED
<ul id="w0" class="nav"><li class="nav-item"><a class="nav-link" href="#">Page1</a></li>
<li class="dropdown nav-item"><a class="dropdown-toggle nav-link" href="#" data-bs-toggle="dropdown" role="button" aria-expanded="false">Dropdown1</a><div id="w1" class="dropdown-menu"><h6 class="dropdown-header">Page2</h6>
<h6 class="dropdown-header">Page3</h6></div></li>
<li class="nav-item"><a class="nav-link" href="#">Page4</a></li></ul>
EXPECTED;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testActive()
{
$this->mockAction('site', 'users');
Nav::$counter = 0;
$out = Nav::widget([
'items' => [
[
'label' => 'Main',
'url' => ['site/index'],
],
[
'label' => 'Admin',
'items' => [
[
'label' => 'Users',
'url' => ['site/users'],
],
[
'label' => 'Roles',
'url' => ['site/roles'],
],
[
'label' => 'Statuses',
'url' => ['site/statuses'],
],
],
],
],
]);
$expected = <<<EXPECTED
<ul id="w0" class="nav"><li class="nav-item"><a class="nav-link" href="/base/index.php?r=site%2Findex">Main</a></li>
<li class="dropdown nav-item"><a class="dropdown-toggle nav-link" href="#" data-bs-toggle="dropdown" role="button" aria-expanded="false">Admin</a><div id="w1" class="dropdown-menu"><a class="dropdown-item active" href="/base/index.php?r=site%2Fusers" aria-current="true">Users</a>
<a class="dropdown-item" href="/base/index.php?r=site%2Froles">Roles</a>
<a class="dropdown-item" href="/base/index.php?r=site%2Fstatuses">Statuses</a></div></li></ul>
EXPECTED;
$this->assertEqualsWithoutLE($expected, $out);
$this->removeMockedAction();
}
/**
* @see https://github.com/yiisoft/yii2-bootstrap/issues/162
*/
public function testExplicitActive()
{
$this->mockAction('site', 'index');
Nav::$counter = 0;
$out = Nav::widget([
'activateItems' => false,
'items' => [
[
'label' => 'Item1',
'active' => true,
],
[
'label' => 'Item2',
'url' => ['site/index'],
],
],
]);
$expected = <<<EXPECTED
<ul id="w0" class="nav"><li class="nav-item"><a class="nav-link" href="#">Item1</a></li>
<li class="nav-item"><a class="nav-link" href="/base/index.php?r=site%2Findex">Item2</a></li></ul>
EXPECTED;
$this->assertEqualsWithoutLE($expected, $out);
$this->removeMockedAction();
}
/**
* @see https://github.com/yiisoft/yii2-bootstrap/issues/162
*/
public function testImplicitActive()
{
$this->mockAction('site', 'index');
Nav::$counter = 0;
$out = Nav::widget([
'items' => [
[
'label' => 'Item1',
'active' => true,
],
[
'label' => 'Item2',
'url' => ['site/index'],
],
],
]);
$expected = <<<EXPECTED
<ul id="w0" class="nav"><li class="nav-item"><a class="nav-link active" href="#">Item1</a></li>
<li class="nav-item"><a class="nav-link active" href="/base/index.php?r=site%2Findex">Item2</a></li></ul>
EXPECTED;
$this->assertEqualsWithoutLE($expected, $out);
$this->removeMockedAction();
}
/**
* @see https://github.com/yiisoft/yii2-bootstrap/issues/162
*/
public function testExplicitActiveSubitems()
{
$this->mockAction('site', 'index');
Nav::$counter = 0;
$out = Nav::widget([
'activateItems' => false,
'items' => [
[
'label' => 'Item1',
],
[
'label' => 'Item2',
'items' => [
[
'label' => 'Page2',
'content' => 'Page2',
'url' => ['site/index'],
],
[
'label' => 'Page3',
'content' => 'Page3',
'active' => true,
],
],
],
],
]);
$expected = <<<EXPECTED
<ul id="w0" class="nav"><li class="nav-item"><a class="nav-link" href="#">Item1</a></li>
<li class="dropdown nav-item"><a class="dropdown-toggle nav-link" href="#" data-bs-toggle="dropdown" role="button" aria-expanded="false">Item2</a><div id="w1" class="dropdown-menu"><a class="dropdown-item" href="/base/index.php?r=site%2Findex">Page2</a>
<h6 class="dropdown-header">Page3</h6></div></li></ul>
EXPECTED;
$this->assertEqualsWithoutLE($expected, $out);
$this->removeMockedAction();
}
/**
* @see https://github.com/yiisoft/yii2-bootstrap/issues/162
*/
public function testImplicitActiveSubitems()
{
$this->mockAction('site', 'index');
Nav::$counter = 0;
$out = Nav::widget([
'items' => [
[
'label' => 'Item1',
],
[
'label' => 'Item2',
'items' => [
[
'label' => 'Page2',
'content' => 'Page2',
'url' => ['site/index'],
],
[
'label' => 'Page3',
'content' => 'Page3',
'active' => true,
],
],
],
],
]);
$expected = <<<EXPECTED
<ul id="w0" class="nav"><li class="nav-item"><a class="nav-link" href="#">Item1</a></li>
<li class="dropdown nav-item"><a class="dropdown-toggle nav-link" href="#" data-bs-toggle="dropdown" role="button" aria-expanded="false">Item2</a><div id="w1" class="dropdown-menu"><a class="dropdown-item active" href="/base/index.php?r=site%2Findex" aria-current="true">Page2</a>
<h6 class="dropdown-header">Page3</h6></div></li></ul>
EXPECTED;
$this->assertEqualsWithoutLE($expected, $out);
$this->removeMockedAction();
}
public function testDisabled()
{
$this->mockAction('site', 'index');
Nav::$counter = 0;
$out = Nav::widget([
'items' => [
[
'label' => 'Item1',
'disabled' => true,
],
[
'label' => 'Item2',
'items' => [
[
'label' => 'Page2',
'content' => 'Page2',
'url' => ['site/index'],
'disabled' => true,
],
[
'label' => 'Page3',
'content' => 'Page3',
'active' => true,
],
],
],
],
]);
$expected = <<<EXPECTED
<ul id="w0" class="nav"><li class="nav-item"><a class="nav-link disabled" href="#" tabindex="-1" aria-disabled="true">Item1</a></li>
<li class="dropdown nav-item"><a class="dropdown-toggle nav-link" href="#" data-bs-toggle="dropdown" role="button" aria-expanded="false">Item2</a><div id="w1" class="dropdown-menu"><a class="dropdown-item disabled" href="/base/index.php?r=site%2Findex" tabindex="-1" aria-disabled="true">Page2</a>
<h6 class="dropdown-header">Page3</h6></div></li></ul>
EXPECTED;
$this->assertEqualsWithoutLE($expected, $out);
$this->removeMockedAction();
}
/**
* @see https://github.com/yiisoft/yii2-bootstrap/issues/96
* @see https://github.com/yiisoft/yii2-bootstrap/issues/157
*/
public function testDeepActivateParents()
{
Nav::$counter = 0;
$out = Nav::widget([
'activateParents' => true,
'items' => [
[
'label' => 'Dropdown',
'items' => [
[
'label' => 'Sub-dropdown',
'items' => [
[
'label' => 'Page',
'content' => 'Page',
'active' => true,
],
],
],
],
],
],
]);
$expected = <<<EXPECTED
<ul id="w0" class="nav"><li class="dropdown nav-item"><a class="dropdown-toggle nav-link active" href="#" data-bs-toggle="dropdown" role="button" aria-expanded="false">Dropdown</a><div id="w1" class="dropdown-menu"><div class="dropdown active" aria-expanded="false">
<a class="dropdown-item dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false" role="button">Sub-dropdown</a>
<div id="w2" class="dropdown-submenu dropdown-menu"><h6 class="dropdown-header">Page</h6></div>
</div></div></li></ul>
EXPECTED;
$this->assertEqualsWithoutLE($expected, $out);
}
protected function setUp(): void
{
$this->mockWebApplication([
'components' => [
'request' => [
'class' => 'yii\web\Request',
'scriptUrl' => '/base/index.php',
'hostInfo' => 'http://example.com/',
'url' => '/base/index.php&r=site%2Fcurrent&id=42',
],
'urlManager' => [
'class' => 'yii\web\UrlManager',
'baseUrl' => '/base',
'scriptUrl' => '/base/index.php',
'hostInfo' => 'http://example.com/',
],
],
]);
}
}

View File

@ -0,0 +1,100 @@
<?php
declare(strict_types=1);
namespace yiiunit\extensions\bootstrap5;
use yii\bootstrap5\Offcanvas;
/**
* @group bootstrap5
*/
class OffcanvasTest extends TestCase
{
public function testBodyOptions()
{
Offcanvas::$counter = 0;
$out = Offcanvas::widget([
'closeButton' => false,
'bodyOptions' => [
'class' => 'offcanvas-body test',
'style' => [
'text-align' => 'center',
],
],
]);
$expected = <<<HTML
<div id="w0" class="offcanvas offcanvas-start" tabindex="-1" data-bs-backdrop="true" data-bs-scroll="false">
<div class="offcanvas-body test" style="text-align: center;">
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testOptions()
{
Offcanvas::$counter = 0;
ob_start();
Offcanvas::begin([
'title' => 'Offcanvas title',
'headerOptions' => [
'data-test' => 'Test',
],
'titleOptions' => [
'tag' => 'h2',
],
'placement' => Offcanvas::PLACEMENT_END,
'backdrop' => false,
'scrolling' => true,
'closeButton' => false,
]);
echo '<p>Woohoo, you\'re reading this text in an offcanvas!</p>';
Offcanvas::end();
$out = ob_get_clean();
$expected = <<<HTML
<div id="w0" class="offcanvas offcanvas-end" tabindex="-1" data-bs-backdrop="false" data-bs-scroll="true" aria-labelledby="w0-label">
<div class="offcanvas-header" data-test="Test">
<h2 id="w0-label" class="offcanvas-title">Offcanvas title</h2>
</div>
<div class="offcanvas-body">
<p>Woohoo, you're reading this text in an offcanvas!</p>
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testTriggerButton()
{
Offcanvas::$counter = 0;
ob_start();
Offcanvas::begin([
'toggleButton' => [
'class' => ['btn', 'btn-primary'],
'label' => 'Launch demo offcanvas',
],
'title' => 'Offcanvas title',
]);
echo '<p>Woohoo, you\'re reading this text in an offcanvas!</p>';
Offcanvas::end();
$out = ob_get_clean();
$this->assertStringContainsString(
'<button type="button" class="btn btn-primary" data-bs-toggle="offcanvas" data-bs-target="#w0" aria-controls="w0">Launch demo offcanvas</button>',
$out,
);
}
}

View File

@ -0,0 +1,72 @@
<?php
declare(strict_types=1);
namespace yiiunit\extensions\bootstrap5;
use Yii;
use yii\bootstrap5\Html;
use yii\bootstrap5\Popover;
use yii\web\View;
/**
* @group bootstrap5
*/
class PopoverTest extends TestCase
{
public function testButtonRender()
{
Popover::$counter = 0;
$out = Popover::widget([
'toggleButton' => [
'class' => ['btn', 'btn-primary'],
],
]);
$expected = <<<HTML
<button type="button" id="w0" class="btn btn-primary">Show</button>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testClientOptions()
{
Popover::$counter = 0;
Popover::widget([
'headerOptions' => [
'class' => ['test-header'],
],
'placement' => Popover::PLACEMENT_BOTTOM,
'title' => 'Test Popover',
]);
$js = Yii::$app->view->js[View::POS_READY];
$this->assertIsArray($js);
$options = array_shift($js);
$this->assertContainsWithoutLE("(new bootstrap.Popover('#w0', {", $options);
$this->assertContainsWithoutLE("id=\u0022w0-popover\u0022", $options);
$this->assertContainsWithoutLE("class=\u0022test-header popover-header\u0022", $options);
$this->assertContainsWithoutLE('"placement":"bottom"', $options);
$this->assertContainsWithoutLE('"title":"Test Popover"', $options);
}
public function testContent()
{
Popover::$counter = 0;
Popover::begin([]);
echo Html::tag('span', 'Test content', [
'class' => ['test-content'],
]);
Popover::end();
$js = Yii::$app->view->js[View::POS_READY];
$this->assertIsArray($js);
$options = array_shift($js);
$this->assertContainsWithoutLE('"content":"\u003Cspan class=\u0022test-content\u0022\u003ETest content\u003C\/span\u003E"', $options);
}
}

View File

@ -0,0 +1,121 @@
<?php
declare(strict_types=1);
namespace yiiunit\extensions\bootstrap5;
use yii\bootstrap5\Progress;
/**
* @group bootstrap5
*/
class ProgressTest extends TestCase
{
public function testSimpleRender()
{
Progress::$counter = 0;
$out = Progress::widget([
'label' => 'Progress',
'percent' => 25,
'barOptions' => [
'class' => 'bg-warning',
],
]);
$expected = <<<HTML
<div id="w0" class="progress">
<div class="bg-warning progress-bar" role="progressbar" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100" style="width: 25%;">Progress</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testRender()
{
Progress::$counter = 0;
$out = Progress::widget([
'bars' => [
[
'label' => 'Progress',
'percent' => 25,
],
],
]);
$expected = <<<HTML
<div id="w0" class="progress">
<div class="progress-bar" role="progressbar" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100" style="width: 25%;">Progress</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testMultiple()
{
Progress::$counter = 0;
$out = Progress::widget([
'bars' => [
[
'label' => '',
'percent' => 15,
],
[
'label' => '',
'percent' => 30,
'options' => [
'class' => ['bg-success'],
],
],
[
'label' => '',
'percent' => 20,
'options' => [
'class' => ['bg-info'],
],
],
],
]);
$expected = <<<HTML
<div id="w0" class="progress">
<div class="progress-bar" role="progressbar" aria-valuenow="15" aria-valuemin="0" aria-valuemax="100" style="width: 15%;"></div>
<div class="bg-success progress-bar" role="progressbar" aria-valuenow="30" aria-valuemin="0" aria-valuemax="100" style="width: 30%;"></div>
<div class="bg-info progress-bar" role="progressbar" aria-valuenow="20" aria-valuemin="0" aria-valuemax="100" style="width: 20%;"></div>
</div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
/**
* @see https://github.com/yiisoft/yii2-bootstrap5/issues/121
*/
public function testRussianLocaleRendering()
{
$this->mockWebApplication([
'language' => 'ru-RU',
'sourceLanguage' => 'en-US',
]);
Progress::$counter = 0;
$out = Progress::widget([
'bars' => [
[
'label' => 'Progress',
'percent' => 25,
],
],
]);
$expected = <<<HTML
<div id="w0" class="progress">
<div class="progress-bar" role="progressbar" aria-valuenow="25" aria-valuemin="0" aria-valuemax="100" style="width: 25%;">Progress</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
}

View File

@ -0,0 +1,490 @@
<?php
declare(strict_types=1);
namespace yiiunit\extensions\bootstrap5;
use yii\bootstrap5\Tabs;
use yii\helpers\Html;
/**
* Tests for Tabs widget
*
* @group bootstrap5
*/
class TabsTest extends TestCase
{
public function testRoleTablist()
{
Tabs::$counter = 0;
$out = Tabs::widget([
'items' => [
[
'label' => 'Page1',
'content' => 'Page1',
],
[
'label' => 'Page2',
'content' => 'Page2',
],
],
]);
$this->assertContainsWithoutLE('<ul id="w0" class="nav nav-tabs" role="tablist">', $out);
}
/**
* Each tab should have a corresponding unique ID
*
* @see https://github.com/yiisoft/yii2/issues/6150
*/
public function testIds()
{
Tabs::$counter = 0;
$out = Tabs::widget([
'items' => [
[
'label' => 'Page1',
'content' => 'Page1',
],
[
'label' => 'Dropdown1',
'items' => [
[
'label' => 'Page2',
'content' => 'Page2',
],
[
'label' => 'Page3',
'content' => 'Page3',
],
],
],
[
'label' => 'Dropdown2',
'items' => [
[
'label' => 'Page4',
'content' => 'Page4',
],
[
'label' => 'Page5',
'content' => 'Page5',
],
],
],
[
'label' => $extAnchor1 = 'External link',
'url' => $extUrl1 = ['//other/route'],
],
[
'label' => 'Dropdown3',
'items' => [
[
'label' => $extAnchor2 = 'External Dropdown Link',
'url' => $extUrl2 = ['//other/dropdown/route'],
],
],
],
],
]);
$page1 = 'w0-tab0';
$page2 = 'w0-dd1-tab0';
$page3 = 'w0-dd1-tab1';
$page4 = 'w0-dd2-tab0';
$page5 = 'w0-dd2-tab1';
$shouldContain = [
'w0', // nav widget container
"#$page1", // Page1
'w1', // Dropdown1
"$page2", // Page2
"$page3", // Page3
'w2', // Dropdown2
"#$page4", // Page4
"#$page5", // Page5
'w3', // Dropdown3
// containers
"id=\"$page1\"",
"id=\"$page2\"",
"id=\"$page3\"",
"id=\"$page4\"",
"id=\"$page5\"",
Html::a($extAnchor1, $extUrl1, [
'class' => 'nav-link',
]),
Html::a($extAnchor2, $extUrl2, [
/*'tabindex' => -1, */
'class' => 'dropdown-item',
]),
];
foreach ($shouldContain as $string) {
$this->assertContainsWithoutLE($string, $out);
}
}
public function testVisible()
{
Tabs::$counter = 0;
$html = Tabs::widget([
'items' => [
[
'label' => 'Page1',
'content' => 'Page1',
],
[
'label' => 'InvisiblePage',
'content' => 'Invisible Page Content',
'visible' => false,
],
[
'label' => 'Dropdown1',
'items' => [
[
'label' => 'Page2',
'content' => 'Page2',
],
[
'label' => 'InvisibleItem',
'content' => 'Invisible Item Content',
'visible' => false,
],
[
'label' => 'Page3',
'content' => 'Page3',
],
[
'label' => 'External Link',
'url' => ['//other/dropdown/route'],
],
[
'label' => 'Invisible External Link',
'url' => ['//other/dropdown/route'],
'visible' => false,
],
],
],
],
]);
$this->assertStringNotContainsString('InvisiblePage', $html);
$this->assertStringNotContainsString('Invisible Page Content', $html);
$this->assertStringNotContainsString('InvisibleItem', $html);
$this->assertStringNotContainsString('Invisible Item Content', $html);
$this->assertStringNotContainsString('Invisible External Link', $html);
}
public function testDisabled()
{
Tabs::$counter = 0;
$html = Tabs::widget([
'items' => [
[
'label' => 'Page1',
'content' => 'Page1',
'disabled' => true,
],
[
'label' => 'Page2',
'content' => 'Page2',
],
[
'label' => 'DisabledPage',
'content' => 'Disabled Page Content',
'disabled' => true,
],
[
'label' => 'Dropdown1',
'items' => [
[
'label' => 'Page2',
'content' => 'Page2',
],
[
'label' => 'DisabledItem',
'content' => 'Disabled Item Content',
'disabled' => true,
],
[
'label' => 'Page3',
'content' => 'Page3',
],
[
'label' => 'External Link',
'url' => ['//other/dropdown/route'],
],
[
'label' => 'Disabled External Link',
'url' => ['//other/dropdown/route'],
'disabled' => true,
],
],
],
],
]);
$this->assertStringContainsString(
'<li class="nav-item"><a class="nav-link disabled" href="#w0-tab0" data-bs-toggle="tab" role="tab" aria-controls="w0-tab0" aria-disabled="true" tabindex="-1">Page1</a></li>',
$html,
);
$this->assertStringContainsString(
'<li class="nav-item"><a class="nav-link active" href="#w0-tab1" data-bs-toggle="tab" role="tab" aria-controls="w0-tab1" aria-selected="true">Page2</a></li>',
$html,
);
$this->assertStringContainsString(
'<li class="nav-item"><a class="nav-link disabled" href="#w0-tab2" data-bs-toggle="tab" role="tab" aria-controls="w0-tab2" aria-disabled="true" tabindex="-1">DisabledPage</a></li>',
$html,
);
$this->assertStringContainsString(
'<a class="dropdown-item disabled" href="#w0-dd3-tab1" data-bs-toggle="tab" role="tab" aria-controls="w0-dd3-tab1" aria-disabled="true" tabindex="-1">DisabledItem</a>',
$html,
);
$this->assertStringContainsString(
'<a class="dropdown-item disabled" href="/index.php?r=other%2Fdropdown%2Froute" tabindex="-1" aria-disabled="true">Disabled External Link</a>',
$html,
);
}
public function testItem()
{
$checkTag = 'article';
$out = Tabs::widget([
'items' => [
[
'label' => 'Page1',
'content' => 'Page1',
],
[
'label' => 'Page2',
'content' => 'Page2',
],
],
'itemOptions' => [
'tag' => $checkTag,
],
'renderTabContent' => true,
]);
$this->assertStringContainsString('<' . $checkTag, $out);
}
public function testRenderView()
{
$out = Tabs::widget([
'items' => [
[
'label' => 'Page1',
'view' => [
'@yiiunit/extensions/bootstrap5/views/tab-test.php',
[
'content' => 'test',
],
],
],
],
]);
$this->assertStringContainsString('<span class="test-content">test</span>', $out);
}
public function testTabContentOptions()
{
$checkAttribute = 'test_attribute';
$checkValue = 'check_attribute';
$out = Tabs::widget([
'items' => [
[
'label' => 'Page1',
'content' => 'Page1',
],
],
'tabContentOptions' => [
$checkAttribute => $checkValue,
],
]);
$this->assertStringContainsString($checkAttribute . '=', $out);
$this->assertStringContainsString($checkValue, $out);
}
public function testActivateFirstVisibleTab()
{
$html = Tabs::widget([
'id' => 'mytab',
'items' => [
[
'label' => 'Tab 1',
'content' => 'some content',
'visible' => false,
],
[
'label' => 'Tab 2',
'content' => 'some content',
'disabled' => true,
],
[
'label' => 'Tab 3',
'content' => 'some content',
],
[
'label' => 'Tab 4',
'content' => 'some content',
],
],
]);
$this->assertStringNotContainsString(
'<li class="nav-item"><a class="nav-link active" href="#mytab-tab0" data-bs-toggle="tab" role="tab" aria-controls="mytab-tab0" aria-selected="true">Tab 1</a></li>',
$html,
);
$this->assertStringNotContainsString(
'<li class="nav-item"><a class="nav-link active" href="#mytab-tab1" data-bs-toggle="tab" role="tab" aria-controls="mytab-tab1" aria-selected="true">Tab 2</a></li>',
$html,
);
$this->assertStringContainsString(
'<li class="nav-item"><a class="nav-link active" href="#mytab-tab2" data-bs-toggle="tab" role="tab" aria-controls="mytab-tab2" aria-selected="true">Tab 3</a></li>',
$html,
);
}
public function testActivateTab()
{
$html = Tabs::widget([
'id' => 'mytab',
'items' => [
[
'label' => 'Tab 1',
'content' => 'some content',
'visible' => false,
],
[
'label' => 'Tab 2',
'content' => 'some content',
],
[
'label' => 'Tab 3',
'content' => 'some content',
'active' => true,
],
[
'label' => 'Tab 4',
'content' => 'some content',
],
],
]);
$this->assertStringContainsString(
'<li class="nav-item"><a class="nav-link active" href="#mytab-tab2" data-bs-toggle="tab" role="tab" aria-controls="mytab-tab2" aria-selected="true">Tab 3</a></li>',
$html,
);
}
public function testTabLabelEncoding()
{
$html = Tabs::widget([
'encodeLabels' => false,
'id' => 'mytab',
'items' => [
[
'label' => 'Tab 1<span>encoded</span>',
'content' => 'some content',
'encode' => true,
],
[
'label' => 'Tab 2<span>not encoded</span>',
'content' => 'some content',
],
[
'label' => 'Tab 3<span>not encoded too</span>',
'content' => 'some content',
],
],
]);
$this->assertStringContainsString('&lt;span&gt;encoded&lt;/span&gt;', $html);
$this->assertStringContainsString('<span>not encoded</span>', $html);
$this->assertStringContainsString('<span>not encoded too</span>', $html);
}
/**
* @see https://github.com/yiisoft/yii2-bootstrap5/issues/108#issuecomment-465219339
*/
public function testIdRendering()
{
Tabs::$counter = 0;
$html = Tabs::widget([
'items' => [
[
'options' => [
'id' => 'pane1',
],
'label' => 'Tab 1',
'content' => '<div>Content 1</div>',
],
[
'label' => 'Tab 2',
'content' => '<div>Content 2</div>',
],
],
]);
$expected = <<<HTML
<ul id="w0" class="nav nav-tabs" role="tablist"><li class="nav-item"><a class="nav-link active" href="#pane1" data-bs-toggle="tab" role="tab" aria-controls="pane1" aria-selected="true">Tab 1</a></li>
<li class="nav-item"><a class="nav-link" href="#w0-tab1" data-bs-toggle="tab" role="tab" aria-controls="w0-tab1" aria-selected="false">Tab 2</a></li></ul>
<div class="tab-content"><div id="pane1" class="tab-pane active"><div>Content 1</div></div>
<div id="w0-tab1" class="tab-pane"><div>Content 2</div></div></div>
HTML;
$this->assertEqualsWithoutLE($expected, $html);
}
public function testHeaderOptions()
{
Tabs::$counter = 0;
$html = Tabs::widget([
'items' => [
[
'label' => 'Tab 1',
'content' => '<div>Content 1</div>',
],
[
'label' => 'Tab 2',
'content' => '<div>Content 2</div>',
'headerOptions' => [
'class' => 'col-6',
],
],
[
'label' => 'Link',
'url' => 'http://www.example.com/',
'headerOptions' => [
'class' => 'col-3',
],
],
],
'options' => [
'class' => 'row',
],
'headerOptions' => [
'class' => 'col',
],
]);
$expected = <<<HTML
<ul id="w0" class="row nav nav-tabs" role="tablist"><li class="col nav-item"><a class="nav-link active" href="#w0-tab0" data-bs-toggle="tab" role="tab" aria-controls="w0-tab0" aria-selected="true">Tab 1</a></li>
<li class="col-6 nav-item"><a class="nav-link" href="#w0-tab1" data-bs-toggle="tab" role="tab" aria-controls="w0-tab1" aria-selected="false">Tab 2</a></li>
<li class="col-3 nav-item"><a class="nav-link" href="http://www.example.com/">Link</a></li></ul>
<div class="tab-content"><div id="w0-tab0" class="tab-pane active"><div>Content 1</div></div>
<div id="w0-tab1" class="tab-pane"><div>Content 2</div></div></div>
HTML;
$this->assertEquals($expected, $html);
}
}

View File

@ -0,0 +1,113 @@
<?php
declare(strict_types=1);
namespace yiiunit\extensions\bootstrap5;
use Yii;
use yii\base\Action;
use yii\base\Module;
use yii\di\Container;
use yii\helpers\ArrayHelper;
use yii\web\Controller;
/**
* This is the base class for all yii framework unit tests.
*/
class TestCase extends \PHPUnit\Framework\TestCase
{
/**
* Asserting two strings equality ignoring line endings
*/
public function assertEqualsWithoutLE(string $expected, string $actual)
{
$expected = str_replace("\r\n", "\n", $expected);
$actual = str_replace("\r\n", "\n", $actual);
$this->assertEquals($expected, $actual);
}
/**
* Asserting two strings equality ignoring line endings
*/
public function assertContainsWithoutLE(string $needle, string $haystack)
{
$needle = str_replace("\r\n", "\n", $needle);
$haystack = str_replace("\r\n", "\n", $haystack);
$this->assertStringContainsString($needle, $haystack);
}
protected function setUp(): void
{
parent::setUp();
$this->mockWebApplication();
}
protected function tearDown(): void
{
parent::tearDown();
$this->destroyApplication();
}
protected function mockWebApplication(array $config = [], string $appClass = '\yii\web\Application')
{
new $appClass(ArrayHelper::merge([
'id' => 'testapp',
'basePath' => __DIR__,
'vendorPath' => dirname(__DIR__) . '/vendor',
'language' => 'en-US',
'aliases' => [
'@bower' => '@vendor/bower-asset',
'@npm' => '@vendor/npm-asset',
],
'components' => [
'i18n' => [
'translations' => [
'yii/bootstrap5*' => [
'class' => 'yii\i18n\GettextMessageSource',
'sourceLanguage' => 'en-US',
'basePath' => '@yii/bootstrap5/messages',
],
],
],
'request' => [
'cookieValidationKey' => 'wefJDF8sfdsfSDefwqdxj9oq',
'scriptFile' => __DIR__ . '/index.php',
'scriptUrl' => '/index.php',
],
],
], $config));
}
/**
* Mocks controller action with parameters
*/
protected function mockAction(string $controllerId, string $actionID, ?string $moduleID = null, array $params = [])
{
Yii::$app->controller = $controller = new Controller($controllerId, Yii::$app);
$controller->actionParams = $params;
$controller->action = new Action($actionID, $controller);
if ($moduleID !== null) {
$controller->module = new Module($moduleID);
}
}
/**
* Removes controller
*/
protected function removeMockedAction()
{
Yii::$app->controller = null;
}
/**
* Destroys application in Yii::$app by setting it to null.
*/
protected function destroyApplication()
{
Yii::$app = null;
Yii::$container = new Container();
}
}

View File

@ -0,0 +1,220 @@
<?php
declare(strict_types=1);
namespace yiiunit\extensions\bootstrap5;
use Yii;
use yii\bootstrap5\Toast;
use yii\web\View;
/**
* @group bootstrap5
*/
class ToastTest extends TestCase
{
public function testBodyOptions()
{
Toast::$counter = 0;
$out = Toast::widget([
'bodyOptions' => [
'class' => 'toast-body test',
'style' => [
'text-align' => 'center',
],
],
]);
$expected = <<<HTML
<div id="w0" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
<div class="toast-header">
<strong class="me-auto"></strong>
<button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
<div class="toast-body test" style="text-align: center;">
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testContainerOptions()
{
Toast::$counter = 0;
ob_start();
Toast::begin([
'title' => 'Toast title',
'dateTime' => time() - 60,
]);
echo 'Woohoo, you\'re reading this text in a toast!';
Toast::end();
$out = ob_get_clean();
$expected = <<<HTML
<div id="w0" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
<div class="toast-header">
<strong class="me-auto">Toast title</strong>
<small class="text-muted">a minute ago</small>
<button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
<div class="toast-body">
Woohoo, you're reading this text in a toast!
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testDateTimeOptions()
{
Toast::$counter = 0;
$out = Toast::widget([
'title' => 'Toast title',
'dateTime' => time() - 60,
'dateTimeOptions' => [
'class' => ['toast-date-time'],
'style' => [
'text-align' => 'right',
],
],
]);
$expected = <<<HTML
<div id="w0" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
<div class="toast-header">
<strong class="me-auto">Toast title</strong>
<small class="toast-date-time text-muted" style="text-align: right;">a minute ago</small>
<button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
<div class="toast-body">
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
public function testTitleOptions()
{
Toast::$counter = 0;
$out = Toast::widget([
'title' => 'Toast title',
'titleOptions' => [
'tag' => 'h5',
'style' => [
'text-align' => 'left',
],
],
]);
$expected = <<<HTML
<div id="w0" class="toast" role="alert" aria-live="assertive" aria-atomic="true">
<div class="toast-header">
<h5 class="me-auto" style="text-align: left;">Toast title</h5>
<button type="button" class="btn-close" data-bs-dismiss="toast" aria-label="Close"></button>
</div>
<div class="toast-body">
</div>
</div>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
/**
* @see https://github.com/yiisoft/yii2-bootstrap5/issues/5
*/
public function testWidgetInitialization()
{
Toast::$counter = 0;
ob_start();
$toast = Toast::begin([
'title' => 'Toast title',
'titleOptions' => [
'tag' => 'h5',
'style' => [
'text-align' => 'left',
],
],
]);
echo 'test';
Toast::end();
ob_get_clean();
$this->assertIsArray($toast->clientOptions);
$this->assertCount(0, $toast->clientOptions);
$js = Yii::$app->view->js[View::POS_READY];
$this->assertIsArray($js);
$options = array_shift($js);
$this->assertContainsWithoutLE("(new bootstrap.Toast('#w0', {}));", $options);
}
/**
* @see https://github.com/yiisoft/yii2-bootstrap5/issues/36
*/
public function testWidgetNoInitialization()
{
Toast::$counter = 0;
ob_start();
$toast = Toast::begin([
'title' => 'Toast title',
'clientOptions' => false,
'titleOptions' => [
'tag' => 'h5',
'style' => [
'text-align' => 'left',
],
],
]);
echo 'test';
Toast::end();
ob_get_clean();
$this->assertFalse($toast->clientOptions);
$this->assertArrayHasKey(View::POS_READY, Yii::$app->view->js);
}
public function testWidgetInitializationWithClientOptions()
{
Toast::$counter = 0;
ob_start();
$toast = Toast::begin([
'title' => 'Toast title',
'clientOptions' => [
'delay' => 1000,
],
'titleOptions' => [
'tag' => 'h5',
'style' => [
'text-align' => 'left',
],
],
]);
echo 'test';
Toast::end();
ob_get_clean();
$this->assertArrayHasKey('delay', $toast->clientOptions);
$this->assertArrayHasKey(View::POS_READY, Yii::$app->view->js);
$js = Yii::$app->view->js[View::POS_READY];
$this->assertIsArray($js);
$options = array_shift($js);
$this->assertContainsWithoutLE("(new bootstrap.Toast('#w0', {\"delay\":1000}));", $options);
}
}

View File

@ -0,0 +1,102 @@
<?php
declare(strict_types=1);
namespace yiiunit\extensions\bootstrap5;
use yii\base\Model;
use yii\bootstrap5\Html;
use yii\bootstrap5\ToggleButtonGroup;
/**
* @group bootstrap5
*/
class ToggleButtonGroupTest extends TestCase
{
public function testCheckbox()
{
Html::$counter = 0;
$html = ToggleButtonGroup::widget([
'type' => ToggleButtonGroup::TYPE_CHECKBOX,
'model' => new ToggleButtonGroupTestModel(),
'attribute' => 'value',
'items' => [
'1' => 'item 1',
'2' => 'item 2',
],
]);
$expectedHtml = <<<HTML
<input type="hidden" name="ToggleButtonGroupTestModel[value]" value=""><div id="togglebuttongrouptestmodel-value" class="btn-group" role="group"><input type="checkbox" id="i0" class="btn-check" name="ToggleButtonGroupTestModel[value][]" value="1" autocomplete="off">
<label class="btn btn-outline-secondary" for="i0">item 1</label>
<input type="checkbox" id="i1" class="btn-check" name="ToggleButtonGroupTestModel[value][]" value="2" autocomplete="off">
<label class="btn btn-outline-secondary" for="i1">item 2</label></div>
HTML;
$this->assertEqualsWithoutLE($expectedHtml, $html);
}
public function testCheckboxChecked()
{
Html::$counter = 0;
$html = ToggleButtonGroup::widget([
'type' => ToggleButtonGroup::TYPE_CHECKBOX,
'model' => new ToggleButtonGroupTestModel([
'value' => '2',
]),
'attribute' => 'value',
'items' => [
'1' => 'item 1',
'2' => 'item 2',
],
]);
$this->assertStringContainsString('<input type="checkbox" id="i1" class="btn-check" name="ToggleButtonGroupTestModel[value][]" value="2" checked autocomplete="off">', $html);
}
public function testRadio()
{
Html::$counter = 0;
$html = ToggleButtonGroup::widget([
'type' => ToggleButtonGroup::TYPE_RADIO,
'model' => new ToggleButtonGroupTestModel(),
'attribute' => 'value',
'items' => [
'1' => 'item 1',
'2' => 'item 2',
],
]);
$expectedHtml = <<<HTML
<input type="hidden" name="ToggleButtonGroupTestModel[value]" value=""><div id="togglebuttongrouptestmodel-value" class="btn-group" role="group"><input type="radio" id="i0" class="btn-check" name="ToggleButtonGroupTestModel[value]" value="1" autocomplete="off">
<label class="btn btn-outline-secondary" for="i0">item 1</label>
<input type="radio" id="i1" class="btn-check" name="ToggleButtonGroupTestModel[value]" value="2" autocomplete="off">
<label class="btn btn-outline-secondary" for="i1">item 2</label></div>
HTML;
$this->assertEqualsWithoutLE($expectedHtml, $html);
}
public function testRadioChecked()
{
Html::$counter = 0;
$html = ToggleButtonGroup::widget([
'type' => ToggleButtonGroup::TYPE_RADIO,
'model' => new ToggleButtonGroupTestModel([
'value' => '2',
]),
'attribute' => 'value',
'items' => [
'1' => 'item 1',
'2' => 'item 2',
],
]);
$this->assertStringContainsString('<input type="radio" id="i1" class="btn-check" name="ToggleButtonGroupTestModel[value]" value="2" checked autocomplete="off">', $html);
}
}
class ToggleButtonGroupTestModel extends Model
{
public $value;
}

View File

@ -0,0 +1,80 @@
<?php
declare(strict_types=1);
/**
* @package yii2-bootstrap5
* @author Simon Karlen <simi.albi@gmail.com>
*/
namespace yiiunit\extensions\bootstrap5;
use yii\bootstrap5\Alert;
use yii\bootstrap5\Breadcrumbs;
class TranslationTest extends TestCase
{
protected function setUp(): void
{
$this->mockWebApplication([
'language' => 'de-CH',
'sourceLanguage' => 'en-US',
'components' => [
'i18n' => [
'translations' => [
'yii/bootstrap5*' => [
'class' => 'yii\i18n\GettextMessageSource',
'sourceLanguage' => 'en-US',
'basePath' => '@yii/bootstrap5/messages',
],
],
],
],
]);
}
public function testTranslatedAlert()
{
Alert::$counter = 0;
$html = Alert::widget([
'body' => '<strong>Heilige Guacamole!</strong> Das ist ein deutscher Test.',
'options' => [
'class' => ['alert-warning'],
],
]);
$expectedHtml = <<<HTML
<div id="w0" class="alert-warning alert alert-dismissible" role="alert">
<strong>Heilige Guacamole!</strong> Das ist ein deutscher Test.
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Schliessen"></button>
</div>
HTML;
$this->assertEqualsWithoutLE($expectedHtml, $html);
}
public function testTranslatedBreadcrumb()
{
Breadcrumbs::$counter = 0;
$out = Breadcrumbs::widget([
'links' => [
[
'label' => 'Library',
'url' => '#',
],
[
'label' => 'Data',
],
],
]);
$expected = <<<HTML
<nav aria-label="breadcrumb"><ol id="w0" class="breadcrumb"><li class="breadcrumb-item"><a href="/index.php">Home</a></li>
<li class="breadcrumb-item"><a href="#">Library</a></li>
<li class="breadcrumb-item active" aria-current="page">Data</li>
</ol></nav>
HTML;
$this->assertEqualsWithoutLE($expected, $out);
}
}

View File

@ -0,0 +1,2 @@
*
!.gitignore

View File

@ -0,0 +1,16 @@
<?php
declare(strict_types=1);
// ensure we get report on all possible php errors
error_reporting(-1);
const YII_ENABLE_ERROR_HANDLER = false;
const YII_DEBUG = true;
$_SERVER['SCRIPT_NAME'] = '/' . __DIR__;
$_SERVER['SCRIPT_FILENAME'] = __FILE__;
require_once(__DIR__ . '/../vendor/autoload.php');
require_once(__DIR__ . '/../vendor/yiisoft/yii2/Yii.php');
Yii::setAlias('@yiiunit/extensions/bootstrap5', __DIR__);
Yii::setAlias('@yii/bootstrap5', dirname(__DIR__) . '/src');

View File

@ -0,0 +1,25 @@
<?php
declare(strict_types=1);
namespace yiiunit\extensions\bootstrap5\data;
use yii\bootstrap5\ActiveField;
/**
* A customized extension from ActiveField
*
* @see \yiiunit\extensions\bootstrap5\ActiveFieldTest::testHorizontalCssClassesOverride()
*
* @author Michael Härtl <haertl.mike@gmail.com>
*/
class ExtendedActiveField extends ActiveField
{
public $horizontalCssClasses = [
'offset' => 'col-md-offset-4',
'label' => 'col-md-4',
'wrapper' => 'col-md-6',
'error' => 'col-md-3',
'hint' => 'col-md-3',
];
}

View File

@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace yiiunit\extensions\bootstrap5\data;
use yii\base\Model;
/**
* @author Daniel Gomez Pan <pana_1990@hotmail.com>
*/
class Singer extends Model
{
public $firstName;
public $lastName;
public $test;
public function rules()
{
return [
[['lastName'],
'default',
'value' => 'Lennon'],
[['lastName'], 'required'],
[['underscore_style'], 'yii\captcha\CaptchaValidator'],
[['test'],
'required',
'when' => function ($model) {
return $model->firstName === 'cebe';
}],
];
}
}

View File

@ -0,0 +1,48 @@
<?php
declare(strict_types=1);
/**
* @package yii2-bootstrap5
* @author Simon Karlen <simi.albi@outlook.com>
*/
namespace yiiunit\extensions\bootstrap5\data;
use yii\base\Model;
class User extends Model
{
public $id;
public $firstName;
public $lastName;
public $username;
public $password;
public function rules()
{
return [
['id', 'integer'],
[['firstName', 'lastName'], 'string'],
[
'username',
'string',
'min' => 4,
],
[
'password',
'string',
'min' => 8,
'max' => '20',
],
[['username', 'password'], 'required'],
];
}
public function attributeHints()
{
return [
'username' => 'Your username must be at least 4 characters long',
'password' => 'Your password must be 8-20 characters long, contain letters and numbers, and must not contain spaces, special characters, or emoji.',
];
}
}

View File

@ -0,0 +1,7 @@
<?php
/** @var yii\web\View $this */
/** @var string $content */
?>
<span class="test-content"><?= $content; ?></span>