diff --git a/composer.json b/composer.json index e75fe08..fe240fb 100644 --- a/composer.json +++ b/composer.json @@ -35,7 +35,6 @@ "scripts": { "test": "phpunit --colors=always", "test:dox": "phpunit --testdox --colors=always", - "test:cov": "phpunit --coverage-html", "test:ci": "phpunit --coverage-text", "cs:fix": "pint -v", "cs:test": "pint --test -v" diff --git a/src/Contracts/Selectable.php b/src/Contracts/Selectable.php index f545f32..48d03be 100644 --- a/src/Contracts/Selectable.php +++ b/src/Contracts/Selectable.php @@ -19,7 +19,7 @@ interface Selectable /** * Add the selected attribute. */ - public function selected(bool $selected = true): static; + public function selected(): static; /** * Add the selected if it fulfill the condition. diff --git a/src/Elements/Button.php b/src/Elements/Button.php index 29acb28..adf8010 100644 --- a/src/Elements/Button.php +++ b/src/Elements/Button.php @@ -4,6 +4,7 @@ namespace Arcanedev\Html\Elements; +use Arcanedev\Html\Elements\Concerns\HasDisabledAttribute; use Arcanedev\Html\Elements\Concerns\HasNameAttribute; use Arcanedev\Html\Elements\Concerns\HasTypeAttribute; use Arcanedev\Html\Elements\Concerns\HasValueAttribute; @@ -20,10 +21,9 @@ class Button extends HtmlElement | ----------------------------------------------------------------- */ + use HasDisabledAttribute; use HasNameAttribute; - use HasTypeAttribute; - use HasValueAttribute; /* ----------------------------------------------------------------- diff --git a/src/Elements/Concerns/HasChildElements.php b/src/Elements/Concerns/HasChildElements.php index 0d0c468..2efdf0f 100644 --- a/src/Elements/Concerns/HasChildElements.php +++ b/src/Elements/Concerns/HasChildElements.php @@ -70,7 +70,7 @@ public function initChildren(): static * * @return $this */ - public function children(mixed $children, ?Closure $mapper = null): static + public function children(mixed $children, Closure|array|null $mapper = null): static { return $this->addChild($children, $mapper); } @@ -80,7 +80,7 @@ public function children(mixed $children, ?Closure $mapper = null): static * * @return $this */ - public function addChild(mixed $child, ?Closure $mapper = null): static + public function addChild(mixed $child, Closure|array|null $mapper = null): static { if ($child === null) { return $this; @@ -98,7 +98,7 @@ public function addChild(mixed $child, ?Closure $mapper = null): static * * @return $this */ - public function setNewChildren(mixed $children, ?Closure $mapper = null): static + public function setNewChildren(mixed $children, Closure|array|null $mapper = null): static { return tap(clone $this) ->initChildren() @@ -110,7 +110,7 @@ public function setNewChildren(mixed $children, ?Closure $mapper = null): static * * @return $this */ - public function prependChild(mixed $children, ?Closure $mapper = null): static + public function prependChild(mixed $children, Closure|array|null $mapper = null): static { return $this->prependChildren($children, $mapper); } @@ -120,7 +120,7 @@ public function prependChild(mixed $children, ?Closure $mapper = null): static * * @return $this */ - public function prependChildren(mixed $children, ?Closure $mapper = null): static + public function prependChildren(mixed $children, Closure|array|null $mapper = null): static { return tap(clone $this, function (HtmlElement $elt) use ($children, $mapper): void { $elt->getChildren() diff --git a/src/Elements/Fieldset.php b/src/Elements/Fieldset.php index 6f149f5..b336e6b 100644 --- a/src/Elements/Fieldset.php +++ b/src/Elements/Fieldset.php @@ -4,6 +4,8 @@ namespace Arcanedev\Html\Elements; +use Arcanedev\Html\Elements\Concerns\HasDisabledAttribute; + /** * Class Fieldset * @@ -11,6 +13,13 @@ */ class Fieldset extends HtmlElement { + /* ----------------------------------------------------------------- + | Properties + | ----------------------------------------------------------------- + */ + + use HasDisabledAttribute; + /* ----------------------------------------------------------------- | Properties | ----------------------------------------------------------------- diff --git a/src/Elements/File.php b/src/Elements/File.php index c2f750d..c5c0f70 100644 --- a/src/Elements/File.php +++ b/src/Elements/File.php @@ -21,10 +21,9 @@ class File extends HtmlElement */ use HasAutofocusAttribute; - use HasNameAttribute; - use HasRequiredAttribute; + /* ----------------------------------------------------------------- | Constants | ----------------------------------------------------------------- diff --git a/src/Elements/HtmlElement.php b/src/Elements/HtmlElement.php index cc09493..2870e1f 100644 --- a/src/Elements/HtmlElement.php +++ b/src/Elements/HtmlElement.php @@ -5,13 +5,11 @@ namespace Arcanedev\Html\Elements; use Arcanedev\Html\Contracts\Elements\HtmlElement as HtmlElementContract; +use Arcanedev\Html\Elements\Concerns\{HasAttributes, HasChildElements, HasConditionalMethods}; use Arcanedev\Html\Entities\Attributes\ClassAttribute; use Arcanedev\Html\Exceptions\InvalidHtmlException; use Arcanedev\Html\Exceptions\MissingTagException; -use Illuminate\Support\Collection; -use Illuminate\Support\HtmlString; -use Illuminate\Support\Str; -use Illuminate\Support\Traits\Macroable; +use Illuminate\Support\{Collection, HtmlString, Str, Traits\Macroable}; /** * Class HtmlElement @@ -29,12 +27,12 @@ class HtmlElement implements HtmlElementContract | ----------------------------------------------------------------- */ - use Concerns\HasAttributes, - Concerns\HasChildElements, - Concerns\HasConditionalMethods, - Macroable { - __call as __callMacro; - } + use HasAttributes; + use HasChildElements; + use HasConditionalMethods; + use Macroable { + __call as __callMacro; + } /* ----------------------------------------------------------------- | Properties @@ -200,11 +198,9 @@ public function text(mixed $text, bool $doubleEncode = true): static } /** - * Add an html child/children. + * Add a html child/children. * * @return $this - * - * @throws InvalidHtmlException */ public function html(mixed $html): static { @@ -295,11 +291,21 @@ protected function setTag(string $tag): static * @throws MissingTagException */ protected function getTag(): string + { + $this->ensureHasTag(); + + return $this->tag; + } + + /** + * Ensure the tag property is defined. + * + * @throws MissingTagException + */ + protected function ensureHasTag(): void { if (empty($this->tag)) { throw MissingTagException::onClass(static::class); } - - return $this->tag; } } diff --git a/src/Elements/I.php b/src/Elements/I.php index 3cf3ff7..872870b 100644 --- a/src/Elements/I.php +++ b/src/Elements/I.php @@ -16,5 +16,8 @@ class I extends HtmlElement | ----------------------------------------------------------------- */ + /** + * The tag type. + */ protected string $tag = 'i'; } diff --git a/src/Elements/ListElement.php b/src/Elements/ListElement.php index db08e54..c79fa68 100644 --- a/src/Elements/ListElement.php +++ b/src/Elements/ListElement.php @@ -11,15 +11,16 @@ */ abstract class ListElement extends HtmlElement { - /** - * Make an item. - */ - abstract protected function makeItem(mixed $value, array $attributes): HtmlElement; /* ----------------------------------------------------------------- | Main Methods | ----------------------------------------------------------------- */ + /** + * Make an item. + */ + abstract protected function makeItem(mixed $value, array $attributes): HtmlElement; + /** * Add an item. * diff --git a/src/Elements/Optgroup.php b/src/Elements/Optgroup.php index e1108d8..77dd48d 100644 --- a/src/Elements/Optgroup.php +++ b/src/Elements/Optgroup.php @@ -4,6 +4,8 @@ namespace Arcanedev\Html\Elements; +use Arcanedev\Html\Elements\Concerns\HasDisabledAttribute; + /** * Class Optgroup * @@ -11,6 +13,13 @@ */ class Optgroup extends HtmlElement { + /* ----------------------------------------------------------------- + | Traits + | ----------------------------------------------------------------- + */ + + use HasDisabledAttribute; + /* ----------------------------------------------------------------- | Properties | ----------------------------------------------------------------- diff --git a/src/Elements/Option.php b/src/Elements/Option.php index 56ee7ff..46bcf80 100644 --- a/src/Elements/Option.php +++ b/src/Elements/Option.php @@ -22,7 +22,6 @@ class Option extends HtmlElement implements Selectable */ use HasDisabledAttribute; - use HasValueAttribute; /* ----------------------------------------------------------------- @@ -44,17 +43,17 @@ class Option extends HtmlElement implements Selectable */ public function selectedIf(bool $condition): static { - return $condition ? $this->selected() : $this->unselected(); + return $condition + ? $this->attribute('selected') + : $this->forgetAttribute('selected'); } /** * Add the selected attribute. */ - public function selected(bool $selected = true): static + public function selected(): static { - return $selected - ? $this->attribute('selected') - : $this->forgetAttribute('selected'); + return $this->selectedIf(true); } /** @@ -62,6 +61,6 @@ public function selected(bool $selected = true): static */ public function unselected(): static { - return $this->selected(false); + return $this->selectedIf(false); } } diff --git a/src/Elements/P.php b/src/Elements/P.php new file mode 100644 index 0000000..fec4095 --- /dev/null +++ b/src/Elements/P.php @@ -0,0 +1,18 @@ +<?php + +declare(strict_types=1); + +namespace Arcanedev\Html\Elements; + +class P extends HtmlElement +{ + /* ----------------------------------------------------------------- + | Properties + | ----------------------------------------------------------------- + */ + + /** + * The tag type. + */ + protected string $tag = 'p'; +} diff --git a/src/Elements/Select.php b/src/Elements/Select.php index aa9fb65..efb1bab 100644 --- a/src/Elements/Select.php +++ b/src/Elements/Select.php @@ -25,13 +25,9 @@ class Select extends HtmlElement */ use HasAutofocusAttribute; - use HasDisabledAttribute; - use HasNameAttribute; - use HasReadonlyAttribute; - use HasRequiredAttribute; /* ----------------------------------------------------------------- @@ -76,7 +72,7 @@ public function options(iterable $options, array $attributes = [], array $groupA { return $this->children( $options, - fn($text, $value) => is_array($text) + fn($text, $value) => is_array($text) || $text instanceof Collection ? $this->makeOptionsGroup($value, $text, $attributes, $groupAttributes[$value] ?? []) : $this->makeOption($value, $text, $attributes[$value] ?? []) ); diff --git a/src/Elements/Textarea.php b/src/Elements/Textarea.php index d8f0eab..4105716 100644 --- a/src/Elements/Textarea.php +++ b/src/Elements/Textarea.php @@ -25,17 +25,11 @@ class Textarea extends HtmlElement */ use HasAutofocusAttribute; - use HasDisabledAttribute; - use HasMinMaxLengthAttributes; - use HasNameAttribute; - use HasPlaceholderAttribute; - use HasReadonlyAttribute; - use HasRequiredAttribute; /* ----------------------------------------------------------------- diff --git a/src/Entities/ChildrenCollection.php b/src/Entities/ChildrenCollection.php index a69bbdc..ab970ca 100644 --- a/src/Entities/ChildrenCollection.php +++ b/src/Entities/ChildrenCollection.php @@ -30,7 +30,7 @@ class ChildrenCollection extends Collection implements Renderable * * @throws InvalidChildException */ - public static function parse(mixed $children, ?Closure $mapper = null): static + public static function parse(mixed $children, Closure|array|null $mapper = null): static { return static::make($children) ->unless($mapper === null, fn(ChildrenCollection $items) => $items->map($mapper)) diff --git a/src/Html.php b/src/Html.php index 1f8d5e3..f66e822 100644 --- a/src/Html.php +++ b/src/Html.php @@ -20,6 +20,7 @@ use Arcanedev\Html\Elements\Legend; use Arcanedev\Html\Elements\Ol; use Arcanedev\Html\Elements\Option; +use Arcanedev\Html\Elements\P; use Arcanedev\Html\Elements\Select; use Arcanedev\Html\Elements\Span; use Arcanedev\Html\Elements\Textarea; @@ -277,6 +278,14 @@ public function option(?string $text = null, mixed $value = null, bool $selected ->selectedIf($selected); } + /** + * Make a paragraph tag. + */ + public function p(HtmlElement|string|null $content = null): P + { + return P::make()->html($content); + } + /** * Make a password input. */ diff --git a/tests/Elements/ATest.php b/tests/Elements/ATest.php index 3c08382..1d031cf 100644 --- a/tests/Elements/ATest.php +++ b/tests/Elements/ATest.php @@ -24,7 +24,7 @@ public function it_can_create(): void { static::assertHtmlStringEqualsHtmlString( '<a></a>', - A::make()->toHtml() + A::make() ); } diff --git a/tests/Elements/ButtonTest.php b/tests/Elements/ButtonTest.php index 9bc7069..87e88ec 100644 --- a/tests/Elements/ButtonTest.php +++ b/tests/Elements/ButtonTest.php @@ -28,6 +28,15 @@ public function it_can_create(): void ); } + #[Test] + public function it_can_create_a_button_with_a_value(): void + { + static::assertHtmlStringEqualsHtmlString( + '<button value="1"></button>', + Button::make()->value(1) + ); + } + #[Test] public function it_can_create_with_custom_type_and_value(): void { @@ -84,4 +93,13 @@ public function it_can_create_with_a_specific_type(): void Button::make()->reset()->html('Reset the form') ); } + + #[Test] + public function it_can_disable_a_button(): void + { + static::assertHtmlStringEqualsHtmlString( + '<button disabled></button>', + Button::make()->disabled() + ); + } } diff --git a/tests/Elements/DivTest.php b/tests/Elements/DivTest.php index 3790ccb..5967141 100644 --- a/tests/Elements/DivTest.php +++ b/tests/Elements/DivTest.php @@ -5,6 +5,13 @@ namespace Arcanedev\Html\Tests\Elements; use Arcanedev\Html\Elements\Div; +use Arcanedev\Html\Elements\HtmlElement; +use Arcanedev\Html\Entities\Attributes\MiscAttribute; +use Arcanedev\Html\Exceptions\InvalidChildException; +use Arcanedev\Html\Exceptions\InvalidHtmlException; +use BadMethodCallException; +use Illuminate\Support\Collection; +use Illuminate\Support\HtmlString; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\Attributes\Test; @@ -36,6 +43,7 @@ public static function getCustomStylesDP(): array ], ]; } + /* ----------------------------------------------------------------- | Tests | ----------------------------------------------------------------- @@ -50,6 +58,402 @@ public function it_can_create(): void ); } + #[Test] + public function it_can_set_an_attribute_with_set_attribute(): void + { + static::assertHtmlStringEqualsHtmlString( + '<div foo="bar"></div>', + Div::make()->attribute('foo', 'bar')->render() + ); + } + + #[Test] + public function it_can_set_an_attribute_to_null(): void + { + static::assertHtmlStringEqualsHtmlString( + '<div foo=""></div>', + Div::make()->attribute('foo')->render() + ); + } + + #[Test] + public function it_can_set_an_attribute_with_attribute(): void + { + static::assertHtmlStringEqualsHtmlString( + '<div foo="bar"></div>', + Div::make()->attribute('foo', 'bar')->render() + ); + } + + #[Test] + public function it_can_set_an_attribute_with_attribute_if(): void + { + static::assertHtmlStringEqualsHtmlString( + '<div foo="bar"></div>', + Div::make()->attributeIf(true, 'foo', 'bar')->attributeIf(false, 'bar', 'baz')->render() + ); + + static::assertHtmlStringEqualsHtmlString( + '<div foo="bar"></div>', + Div::make()->attributeUnless(false, 'foo', 'bar')->attributeUnless(true, 'bar', 'baz')->render() + ); + } + + #[Test] + public function it_can_set_an_class_with_class_if(): void + { + static::assertHtmlStringEqualsHtmlString( + '<div class="bar"></div>', + Div::make()->classIf(true, 'bar')->classIf(false, 'baz')->render() + ); + } + + #[Test] + public function it_can_not_accept_any_if_method(): void + { + $this->expectException(BadMethodCallException::class); + + Div::make()->barIf(true, 'bar')->render(); + } + + #[Test] + public function it_can_forget_an_attribute(): void + { + static::assertHtmlStringEqualsHtmlString( + '<div></div>', + Div::make()->attribute('foo', 'bar')->forgetAttribute('foo')->render() + ); + } + + #[Test] + public function it_can_get_an_attribute(): void + { + $element = Div::make()->attribute('foo', 'bar'); + + static::assertTrue($element->hasAttribute('foo')); + + $attribute = $element->getAttribute('foo'); + + static::assertInstanceOf(MiscAttribute::class, $attribute); + static::assertSame('foo', $attribute->name()); + static::assertSame('bar', $attribute->value()); + } + + #[Test] + public function it_must_return_null_if_an_attribute_does_not_exists(): void + { + $element = Div::make(); + + static::assertFalse($element->hasAttribute('foo')); + static::assertNull($element->getAttribute('foo')); + } + + #[Test] + public function it_can_set_an_id(): void + { + static::assertHtmlStringEqualsHtmlString( + '<div id="main"></div>', + Div::make()->id('main')->render() + ); + } + + #[Test] + public function multiple_attributes_can_be_set_with_attributes(): void + { + static::assertHtmlStringEqualsHtmlString( + '<div foo bar="baz"></div>', + Div::make()->attributes(['foo', 'bar' => 'baz'])->render() + ); + } + + #[Test] + public function it_can_add_a_class_with_add_class(): void + { + static::assertHtmlStringEqualsHtmlString( + '<div class="foo"></div>', + Div::make()->class('foo')->render() + ); + + static::assertHtmlStringEqualsHtmlString( + '<div class="foo bar"></div>', + Div::make()->class(['foo', 'bar'])->render() + ); + + static::assertHtmlStringEqualsHtmlString( + '<div class="foo"></div>', + Div::make()->class(['foo', 'bar' => false])->render() + ); + } + + #[Test] + public function it_can_add_a_class_with_class(): void + { + static::assertHtmlStringEqualsHtmlString( + '<div class="foo"></div>', + Div::make()->class('foo')->render() + ); + } + + #[Test] + public function it_can_set_style_from_a_string(): void + { + static::assertHtmlStringEqualsHtmlString( + '<div style="color: red"></div>', + Div::make()->style('color: red')->render() + ); + } + + #[Test] + public function it_can_set_style_from_an_array(): void + { + static::assertHtmlStringEqualsHtmlString( + '<div style="color: red"></div>', + Div::make()->style(['color' => 'red'])->render() + ); + } + + #[Test] + public function it_can_set_text(): void + { + static::assertHtmlStringEqualsHtmlString( + '<div>Hi & Bye</div>', + Div::make()->text('Hi & Bye')->render() + ); + } + + #[Test] + public function it_can_set_html(): void + { + static::assertHtmlStringEqualsHtmlString( + '<div><span>Yo</span></div>', + Div::make()->html('<span>Yo</span>')->render() + ); + } + + #[Test] + public function it_can_set_html_from_htmlstring(): void + { + static::assertHtmlStringEqualsHtmlString( + '<div><span>Yo</span></div>', + Div::make()->html(new HtmlString('<span>Yo</span>'))->render() + ); + } + + #[Test] + public function it_cant_set_html_if_its_not_an_html_element(): void + { + $this->expectException(InvalidChildException::class); + + Div::make()->html(true)->render(); + } + + #[Test] + public function setting_text_overwrites_existing_children(): void + { + static::assertHtmlStringEqualsHtmlString( + '<div>Hi</div>', + Div::make()->addChild(Div::make())->text('Hi')->render() + ); + } + + #[Test] + public function it_cant_add_child_if_its_not_an_html_element_or_a_string(): void + { + $this->expectException(InvalidChildException::class); + + Div::make()->addChild(true)->render(); + } + + #[Test] + public function it_cant_set_text_if_its_a_void_element(): void + { + $this->expectException(InvalidHtmlException::class); + $this->expectExceptionMessage("Can't set inner contents on `img` because it's a void element"); + + $img = new class () extends HtmlElement { + protected string $tag = 'img'; + }; + + $img->text('Hi'); + } + + #[Test] + public function it_can_add_a_child_from_a_string(): void + { + static::assertHtmlStringEqualsHtmlString( + '<div>Hello</div>', + Div::make()->addChild('Hello') + ); + } + + #[Test] + public function it_can_add_a_child_from_an_element(): void + { + static::assertHtmlStringEqualsHtmlString( + '<div><div>Hello</div></div>', + Div::make()->addChild(Div::make()->text('Hello')) + ); + } + + #[Test] + public function it_can_add_children_from_an_array_of_strings(): void + { + static::assertHtmlStringEqualsHtmlString( + '<div>Helloworld</div>', + Div::make()->addChild(['Hello', 'world']) + ); + } + + #[Test] + public function it_can_add_children_from_an_array_of_elements(): void + { + static::assertHtmlStringEqualsHtmlString( + '<div><div>Hello</div><div>World</div></div>', + Div::make()->children([Div::make()->text('Hello'), Div::make()->text('World')]) + ); + } + + #[Test] + public function it_can_add_children_from_an_iterable(): void + { + $children = Collection::make([Div::make()->text('Hello'), Div::make()->text('World')]); + + static::assertHtmlStringEqualsHtmlString( + '<div><div>Hello</div><div>World</div></div>', + Div::make()->addChild($children) + ); + } + + #[Test] + public function it_doesnt_add_a_child_if_the_child_is_null(): void + { + static::assertHtmlStringEqualsHtmlString( + '<div></div>', + Div::make()->addChild(null) + ); + } + + #[Test] + public function it_can_transform_children_when_they_are_added(): void + { + static::assertHtmlStringEqualsHtmlString( + '<div><div>Hello</div><div>World</div></div>', + Div::make()->children(['Hello', 'World'], [$this, 'wrapInDiv']) + ); + + static::assertHtmlStringEqualsHtmlString( + '<div><div>Hello</div><div>World</div></div>', + Div::make()->children(['Hello', 'World'], [$this, 'wrapInDiv']) + ); + + static::assertHtmlStringEqualsHtmlString( + '<div><div>Hello</div><div>World</div></div>', + Div::make()->children(['Hello', 'World'], [$this, 'wrapInDiv']) + ); + + static::assertHtmlStringEqualsHtmlString( + '<div><div>Hello</div><div>World</div></div>', + Div::make()->children(['Hello', 'World'], [$this, 'wrapInDiv']) + ); + } + + #[Test] + public function it_can_add_a_child_with_add_child(): void + { + static::assertHtmlStringEqualsHtmlString( + '<div><div>Hello</div></div>', + Div::make()->addChild(Div::make()->text('Hello')) + ); + } + + #[Test] + public function it_can_add_a_child_with_child(): void + { + static::assertHtmlStringEqualsHtmlString( + '<div><div>Hello</div></div>', + Div::make()->addChild(Div::make()->text('Hello')) + ); + } + + #[Test] + public function it_can_add_children_with_children(): void + { + static::assertHtmlStringEqualsHtmlString( + '<div><div>Hello</div></div>', + Div::make()->children(Div::make()->text('Hello')) + ); + } + + #[Test] + public function it_can_prepend_children_with_prepend_children(): void + { + static::assertHtmlStringEqualsHtmlString( + '<div><div>World</div><div>Hello</div></div>', + Div::make() + ->children(Div::make()->text('Hello')) + ->prependChildren(Div::make()->text('World')) + ); + } + + #[Test] + public function it_can_prepend_children_with_prepend_child(): void + { + static::assertHtmlStringEqualsHtmlString( + '<div><div>World</div><div>Hello</div></div>', + Div::make() + ->addChild(Div::make()->text('Hello')) + ->prependChild(Div::make()->text('World')) + ); + } + + #[Test] + public function it_can_transform_children_when_they_are_prepended(): void + { + static::assertHtmlStringEqualsHtmlString( + '<div><div>World</div><div>Hello</div></div>', + Div::make() + ->addChild(Div::make()->text('Hello')) + ->prependChildren(['World'], [$this, 'wrapInDiv']) + ); + + static::assertHtmlStringEqualsHtmlString( + '<div><div>World</div><div>Hello</div></div>', + Div::make() + ->addChild(Div::make()->text('Hello')) + ->prependChild('World', [$this, 'wrapInDiv']) + ); + } + + #[Test] + public function it_can_conditionally_transform_an_element(): void + { + $div = Div::make() + ->if(true, fn(Div $div) => $div->class('foo')) + ->if(false, fn(Div $div) => $div->class('bar')); + + static::assertHtmlStringEqualsHtmlString('<div class="foo"></div>', $div); + + $div = Div::make() + ->unless(false, fn(Div $div) => $div->class('foo')) + ->unless(true, fn(Div $div) => $div->class('bar')); + + static::assertHtmlStringEqualsHtmlString('<div class="foo"></div>', $div); + } + + public function wrapInDiv(string $text): Div + { + return Div::make()->text($text); + } + + #[Test] + public function it_can_set_a_data_attribute(): void + { + static::assertHtmlStringEqualsHtmlString( + '<div data-foo="bar"></div>', + Div::make()->data('foo', 'bar')->render() + ); + } + #[Test] #[DataProvider('getCustomStylesDP')] public function it_can_create_with_custom_styles(array $styles, string $expected): void diff --git a/tests/Elements/FieldsetTest.php b/tests/Elements/FieldsetTest.php index 057e6ba..177f3cf 100644 --- a/tests/Elements/FieldsetTest.php +++ b/tests/Elements/FieldsetTest.php @@ -36,4 +36,13 @@ public function it_can_add_a_legend_to_the_fieldset(): void Fieldset::make()->legend('Legend') ); } + + #[Test] + public function it_can_disable_a_fieldset(): void + { + $this->assertHtmlStringEqualsHtmlString( + '<fieldset disabled></fieldset>', + Fieldset::make()->disabled() + ); + } } diff --git a/tests/Elements/HtmlElementTest.php b/tests/Elements/HtmlElementTest.php index c67a8a2..089a2c0 100644 --- a/tests/Elements/HtmlElementTest.php +++ b/tests/Elements/HtmlElementTest.php @@ -5,6 +5,7 @@ namespace Arcanedev\Html\Tests\Elements; use Arcanedev\Html\Elements\HtmlElement; +use Arcanedev\Html\Exceptions\MissingTagException; use PHPUnit\Framework\Attributes\Test; /** @@ -19,6 +20,16 @@ class HtmlElementTest extends TestCase | ----------------------------------------------------------------- */ + #[Test] + public function it_cant_be_instantiated_without_a_tag_name_on_the_class(): void + { + static::expectException(MissingTagException::class); + + $element = new class () extends HtmlElement {}; + + $element->render(); + } + #[Test] public function it_can_register_a_macro(): void { diff --git a/tests/Elements/InputTest.php b/tests/Elements/InputTest.php index 462e131..34e2cea 100644 --- a/tests/Elements/InputTest.php +++ b/tests/Elements/InputTest.php @@ -146,6 +146,15 @@ public function it_can_uncheck(): void ); } + #[Test] + public function it_can_disable_an_input(): void + { + $this->assertHtmlStringEqualsHtmlString( + '<input type="checkbox" disabled>', + Input::make()->type('checkbox')->disabled() + ); + } + #[Test] public function it_can_create_with_builder(): void { diff --git a/tests/Elements/OptgroupTest.php b/tests/Elements/OptgroupTest.php index 4861e76..6cf0408 100644 --- a/tests/Elements/OptgroupTest.php +++ b/tests/Elements/OptgroupTest.php @@ -36,4 +36,13 @@ public function it_can_create_with_a_label(): void Optgroup::make()->label('Cats') ); } + + #[Test] + public function it_can_disable_an_optgroup(): void + { + $this->assertHtmlStringEqualsHtmlString( + '<optgroup disabled></optgroup>', + Optgroup::make()->disabled() + ); + } } diff --git a/tests/Elements/OptionTest.php b/tests/Elements/OptionTest.php index 93500d5..2d5d6c2 100644 --- a/tests/Elements/OptionTest.php +++ b/tests/Elements/OptionTest.php @@ -24,7 +24,7 @@ public function it_can_render_an_empty_version_itself(): void { static::assertHtmlStringEqualsHtmlString( '<option></option>', - Option::make()->render() + Option::make() ); } @@ -44,6 +44,11 @@ public function it_can_render_itself_in_a_selected_state(): void '<option selected value="0">Choose...</option>', Option::make()->value('0')->text('Choose...')->selected() ); + + static::assertHtmlStringEqualsHtmlString( + '<option selected value="0">Choose...</option>', + Option::make()->value('0')->text('Choose...')->selected() + ); } #[Test] diff --git a/tests/Elements/PTest.php b/tests/Elements/PTest.php new file mode 100644 index 0000000..7760ff5 --- /dev/null +++ b/tests/Elements/PTest.php @@ -0,0 +1,30 @@ +<?php + +declare(strict_types=1); + +namespace Arcanedev\Html\Tests\Elements; + +use Arcanedev\Html\Elements\P; +use PHPUnit\Framework\Attributes\Test; + +/** + * Class PTest + * + * @author ARCANEDEV <arcanedev.maroc@gmail.com> + */ +class PTest extends TestCase +{ + /* ----------------------------------------------------------------- + | Tests + | ----------------------------------------------------------------- + */ + + #[Test] + public function it_can_create_an_i_element(): void + { + static::assertHtmlStringEqualsHtmlString( + '<p></p>', + P::make() + ); + } +} diff --git a/tests/Elements/TextareaTest.php b/tests/Elements/TextareaTest.php index 70f0590..b76d1e9 100644 --- a/tests/Elements/TextareaTest.php +++ b/tests/Elements/TextareaTest.php @@ -81,4 +81,94 @@ public function it_can_set_the_size(): void Textarea::make()->value('My epic content')->size('60x15') ); } + + #[Test] + public function it_can_create_a_textarea_that_is_required_when_passing_true(): void + { + $this->assertHtmlStringEqualsHtmlString( + '<textarea required>My epic</textarea>', + Textarea::make()->value('My epic')->required(true) + ); + } + + #[Test] + public function it_wont_create_a_textarea_that_is_required_when_passing_false(): void + { + $this->assertHtmlStringEqualsHtmlString( + '<textarea>My epic</textarea>', + Textarea::make()->value('My epic')->required(false) + ); + } + + #[Test] + public function it_can_create_a_disabled_textarea(): void + { + $this->assertHtmlStringEqualsHtmlString( + '<textarea disabled>My epic</textarea>', + Textarea::make()->value('My epic')->disabled() + ); + } + + #[Test] + public function it_can_create_a_textarea_that_is_disabled_when_passing_true(): void + { + $this->assertHtmlStringEqualsHtmlString( + '<textarea disabled>My epic</textarea>', + Textarea::make()->value('My epic')->disabled(true) + ); + } + + #[Test] + public function it_wont_create_a_textarea_that_is_disabled_when_passing_false(): void + { + $this->assertHtmlStringEqualsHtmlString( + '<textarea>My epic</textarea>', + Textarea::make()->value('My epic')->disabled(false) + ); + } + + #[Test] + public function it_can_create_a_readonly_textarea(): void + { + $this->assertHtmlStringEqualsHtmlString( + '<textarea readonly>My epic</textarea>', + Textarea::make()->value('My epic')->isReadonly() + ); + } + + #[Test] + public function it_can_create_a_textarea_that_is_readonly_when_passing_true(): void + { + $this->assertHtmlStringEqualsHtmlString( + '<textarea readonly>My epic</textarea>', + Textarea::make()->value('My epic')->isReadonly(true) + ); + } + + #[Test] + public function it_wont_create_a_textarea_that_is_readonly_when_passing_false(): void + { + $this->assertHtmlStringEqualsHtmlString( + '<textarea>My epic</textarea>', + Textarea::make()->value('My epic')->isReadonly(false) + ); + } + + #[Test] + public function it_can_create_a_textarea_with_maxlength(): void + { + $this->assertHtmlStringEqualsHtmlString( + '<textarea maxlength="25">My epic</textarea>', + Textarea::make()->value('My epic')->maxlength(25) + ); + } + + #[Test] + public function it_can_create_a_textarea_with_minlength(): void + { + $this->assertHtmlStringEqualsHtmlString( + '<textarea minlength="25">My epic</textarea>', + Textarea::make()->value('My epic')->minlength(25) + ); + } } diff --git a/tests/Entities/AttributesTest.php b/tests/Entities/AttributesTest.php index 74a0b30..7e4ffd0 100644 --- a/tests/Entities/AttributesTest.php +++ b/tests/Entities/AttributesTest.php @@ -35,7 +35,10 @@ public function it_accepts_classes_as_strings(): void { $attributes = (new Attributes())->addClass('foo bar'); - static::assertEquals(['class' => 'foo bar'], $attributes->toArray()); + $actual = $attributes->toArray(); + + static::assertArrayHasKey('class', $actual); + static::assertEquals(['class' => 'foo bar'], $actual); } #[Test] @@ -43,7 +46,10 @@ public function it_accepts_classes_as_an_array(): void { $attributes = (new Attributes())->addClass(['foo', 'bar']); - static::assertEquals(['class' => 'foo bar'], $attributes->toArray()); + $actual = $attributes->toArray(); + + static::assertArrayHasKey('class', $actual); + static::assertEquals(['class' => 'foo bar'], $actual); } #[Test] @@ -54,7 +60,10 @@ public function it_can_add_classes_conditionally_with_an_associative_array(): vo 'bar' => false, ]); - static::assertEquals(['class' => 'foo'], $attributes->toArray()); + $actual = $attributes->toArray(); + + static::assertArrayHasKey('class', $actual); + static::assertEquals(['class' => 'foo'], $actual); } #[Test] @@ -66,7 +75,10 @@ public function it_can_simultaneously_add_classes_conditionally_and_non_conditio 'baz', ]); - static::assertEquals(['class' => 'foo baz'], $attributes->toArray()); + $actual = $attributes->toArray(); + + static::assertArrayHasKey('class', $actual); + static::assertEquals(['class' => 'foo baz'], $actual); } #[Test] @@ -76,10 +88,11 @@ public function it_accepts_attributes(): void $attributes->set('href', '#'); $attributes->set('class', 'foobar'); - static::assertEquals( - ['href' => '#', 'class' => 'foobar'], - $attributes->toArray() - ); + $actual = $attributes->toArray(); + + static::assertArrayHasKey('href', $actual); + static::assertArrayHasKey('class', $actual); + static::assertEquals(['href' => '#', 'class' => 'foobar'], $actual); } #[Test] @@ -87,10 +100,10 @@ public function it_accepts_attributes_without_values(): void { $attributes = (new Attributes())->set('required'); - static::assertEquals( - ['required' => null], - $attributes->toArray() - ); + $actual = $attributes->toArray(); + + static::assertArrayHasKey('required', $actual); + static::assertEquals(['required' => null], $actual); } #[Test] @@ -159,10 +172,12 @@ public function it_accepts_multiple_attributes(): void 'required', ]); - static::assertEquals( - ['name' => 'email', 'class' => 'foobar', 'required' => null], - $attributes->toArray() - ); + $actual = $attributes->toArray(); + + static::assertArrayHasKey('name', $actual); + static::assertArrayHasKey('class', $actual); + static::assertArrayHasKey('required', $actual); + static::assertEquals(['name' => 'email', 'class' => 'foobar', 'required' => null], $actual); } #[Test]