From 086408929d1bacc968a093bed20b2077cee8317e Mon Sep 17 00:00:00 2001 From: Jamie York Date: Tue, 24 Jun 2025 18:32:14 +0100 Subject: [PATCH 01/15] no code --- src/Dom/AssertableDocument.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Dom/AssertableDocument.php b/src/Dom/AssertableDocument.php index feeae00..f18cdbd 100644 --- a/src/Dom/AssertableDocument.php +++ b/src/Dom/AssertableDocument.php @@ -111,7 +111,7 @@ private static function promoteErrorsToExceptions(callable $callback): mixed set_error_handler(function (int $severity, string $message, string $file, int $line): never { throw new UnableToCreateAssertableDocument( 'Unable to create assertable HTML document.', - previous: new ErrorException($message, $severity, $severity, $file, $line), + previous: new ErrorException($message, 0, $severity, $file, $line), ); }); From 25413559936c967cc53b0cdb6e92660974f9f01d Mon Sep 17 00:00:00 2001 From: Jamie York Date: Tue, 24 Jun 2025 20:25:13 +0100 Subject: [PATCH 02/15] basic promotable element outline --- src/Contracts/PromotableAssertableElement.php | 14 ++++++++ src/Dom/AssertableDocument.php | 4 +-- src/Dom/AssertableElement.php | 6 ++++ src/Dom/AssertableElementPromoter.php | 33 +++++++++++++++++++ src/Dom/AssertableElementsList.php | 2 +- src/Dom/Elements/AssertableForm.php | 18 ++++++++++ 6 files changed, 74 insertions(+), 3 deletions(-) create mode 100644 src/Contracts/PromotableAssertableElement.php create mode 100644 src/Dom/AssertableElementPromoter.php create mode 100644 src/Dom/Elements/AssertableForm.php diff --git a/src/Contracts/PromotableAssertableElement.php b/src/Contracts/PromotableAssertableElement.php new file mode 100644 index 0000000..1a3f10a --- /dev/null +++ b/src/Contracts/PromotableAssertableElement.php @@ -0,0 +1,14 @@ +promote(); } /** Return assertable elements matching the given selector. */ @@ -95,7 +95,7 @@ public function getElementById(string $id): AssertableElement )); } - return new AssertableElement($element); + return new AssertableElement($element)->promote(); } /** Return assertable elements matching the given tag. */ diff --git a/src/Dom/AssertableElement.php b/src/Dom/AssertableElement.php index f9aa9df..ff8acb7 100644 --- a/src/Dom/AssertableElement.php +++ b/src/Dom/AssertableElement.php @@ -57,6 +57,12 @@ private function getElement(): HTMLElement|Element return $this->element; } + /** Promote this assertable element to an element-specific assertable element, if possible. */ + public function promote(): static + { + return new AssertableElementPromoter($this->getElement())->promote() ?? $this; + } + /** Get the assertable element HTML. */ public function getHtml(): string { diff --git a/src/Dom/AssertableElementPromoter.php b/src/Dom/AssertableElementPromoter.php new file mode 100644 index 0000000..df22c5f --- /dev/null +++ b/src/Dom/AssertableElementPromoter.php @@ -0,0 +1,33 @@ + $customElement::shouldPromote($this->element), + ); + + return $match ? new $match($this->element) : null; + } +} diff --git a/src/Dom/AssertableElementsList.php b/src/Dom/AssertableElementsList.php index 1f6ea78..067e61e 100644 --- a/src/Dom/AssertableElementsList.php +++ b/src/Dom/AssertableElementsList.php @@ -33,7 +33,7 @@ public function __construct(NodeList|HTMLCollection $nodes) { $this->elements = array_values( array_map( - fn (HTMLElement|Element $element): AssertableElement => new AssertableElement($element), + fn (HTMLElement|Element $element): AssertableElement => new AssertableElement($element)->promote(), $nodes instanceof NodeList ? iterator_to_array($nodes) : $this->htmlCollectionToArray($nodes), diff --git a/src/Dom/Elements/AssertableForm.php b/src/Dom/Elements/AssertableForm.php new file mode 100644 index 0000000..eb6148f --- /dev/null +++ b/src/Dom/Elements/AssertableForm.php @@ -0,0 +1,18 @@ +tagName === 'FORM'; + } +} From 11c09dcc26931196265d5aa3f6c9c728ff997586 Mon Sep 17 00:00:00 2001 From: Jamie York Date: Tue, 24 Jun 2025 20:25:51 +0100 Subject: [PATCH 03/15] switch promote terminology to convert elsewhere for clarity --- src/Dom/AssertableDocument.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Dom/AssertableDocument.php b/src/Dom/AssertableDocument.php index f558e6c..faf265f 100644 --- a/src/Dom/AssertableDocument.php +++ b/src/Dom/AssertableDocument.php @@ -57,13 +57,13 @@ public function dd(): never /** Create an assertable document from a file. */ public static function createFromFile(string $path, int $options = 0, ?string $overrideEncoding = null): self { - return self::promoteErrorsToExceptions(fn () => new self(HTMLDocument::createFromFile($path, $options, $overrideEncoding))); + return self::convertErrorsToExceptions(fn () => new self(HTMLDocument::createFromFile($path, $options, $overrideEncoding))); } /** Create an assertable document from a string. */ public static function createFromString(string $source, int $options = 0, ?string $overrideEncoding = null): self { - return self::promoteErrorsToExceptions(fn () => new self(HTMLDocument::createFromString($source, $options, $overrideEncoding))); + return self::convertErrorsToExceptions(fn () => new self(HTMLDocument::createFromString($source, $options, $overrideEncoding))); } /** Return the assertable element matching the given selector. */ @@ -104,8 +104,8 @@ public function getElementsByTagName(string $tag): AssertableElementsList return new AssertableElementsList($this->document->getElementsByTagName($tag)); } - /** Promote any PHP errors that occur in the given callback to custom exceptions. */ - private static function promoteErrorsToExceptions(callable $callback): mixed + /** Convert any PHP errors that occur in the given callback to custom exceptions. */ + private static function convertErrorsToExceptions(callable $callback): mixed { try { set_error_handler(function (int $severity, string $message, string $file, int $line): never { From a2daeaf223e00e22b4da0e55067fd3ae4278137c Mon Sep 17 00:00:00 2001 From: Jamie York Date: Tue, 24 Jun 2025 20:38:18 +0100 Subject: [PATCH 04/15] test promote --- .../Dom/AssertableElementPromoterTest.php | 38 +++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 tests/Unit/Dom/AssertableElementPromoterTest.php diff --git a/tests/Unit/Dom/AssertableElementPromoterTest.php b/tests/Unit/Dom/AssertableElementPromoterTest.php new file mode 100644 index 0000000..806f03f --- /dev/null +++ b/tests/Unit/Dom/AssertableElementPromoterTest.php @@ -0,0 +1,38 @@ +assertInstanceOf($class, new AssertableElementPromoter($this->getElement($html))->promote()); + } + + public static function promote_data_provider(): iterable + { + yield 'form' => ['
', AssertableForm::class]; + } + + /* + |-------------------------------------------------------------------------- + | Test Helper + |-------------------------------------------------------------------------- + */ + + private function getElement(string $html): HTMLElement|Element + { + return HTMLDocument::createFromString($html, LIBXML_HTML_NOIMPLIED)->querySelector('*:first-of-type'); + } +} From 60331808728fac78239d294923d05c70db0cd03e Mon Sep 17 00:00:00 2001 From: Jamie York Date: Tue, 24 Jun 2025 20:59:01 +0100 Subject: [PATCH 05/15] comment --- src/Dom/AssertableElement.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Dom/AssertableElement.php b/src/Dom/AssertableElement.php index f28215f..e54b42d 100644 --- a/src/Dom/AssertableElement.php +++ b/src/Dom/AssertableElement.php @@ -57,7 +57,7 @@ private function getElement(): HTMLElement|Element return $this->element; } - /** Promote this assertable element to an element-specific assertable element, if possible. */ + /** Promote this assertable element to an element-specific equivalent assertable element, if possible. */ public function promote(): static { return new AssertableElementPromoter($this->getElement())->promote() ?? $this; From f17cfd39a091efd18e6a9af85ce47e6e53bd3708 Mon Sep 17 00:00:00 2001 From: Jamie York Date: Tue, 24 Jun 2025 21:16:09 +0100 Subject: [PATCH 06/15] assertable form test wip --- tests/Integration/AssertableFormTest.php | 29 ++++++++++++++++++++++++ tests/Integration/AssertableHtmlTest.php | 8 +------ 2 files changed, 30 insertions(+), 7 deletions(-) create mode 100644 tests/Integration/AssertableFormTest.php diff --git a/tests/Integration/AssertableFormTest.php b/tests/Integration/AssertableFormTest.php new file mode 100644 index 0000000..dc81841 --- /dev/null +++ b/tests/Integration/AssertableFormTest.php @@ -0,0 +1,29 @@ +markTestSkipped('@todo'); + + $html = AssertableDocument::createFromString(<<<'HTML' +
+ + + +
+ HTML, LIBXML_HTML_NOIMPLIED); + + $html->one('form', function (AssertableForm $form) { + $form->dump(); + }); + } +} diff --git a/tests/Integration/AssertableHtmlTest.php b/tests/Integration/AssertableHtmlTest.php index 69c6f3a..a929687 100644 --- a/tests/Integration/AssertableHtmlTest.php +++ b/tests/Integration/AssertableHtmlTest.php @@ -11,6 +11,7 @@ use Ziadoz\AssertableHtml\Dom\AssertableElement; use Ziadoz\AssertableHtml\Dom\AssertableElementsList; use Ziadoz\AssertableHtml\Dom\AssertableText; +use Ziadoz\AssertableHtml\Dom\Elements\AssertableForm; class AssertableHtmlTest extends TestCase { @@ -41,13 +42,6 @@ public function test_assertable_html(): void
  • Baz
  • - -
    - - - -
    - I am a web component. From 50fad225d8c4efd9ed600030af3e0096b91df7a3 Mon Sep 17 00:00:00 2001 From: Jamie York Date: Tue, 24 Jun 2025 21:16:16 +0100 Subject: [PATCH 07/15] pint --- tests/Integration/AssertableHtmlTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/Integration/AssertableHtmlTest.php b/tests/Integration/AssertableHtmlTest.php index a929687..f894f0a 100644 --- a/tests/Integration/AssertableHtmlTest.php +++ b/tests/Integration/AssertableHtmlTest.php @@ -11,7 +11,6 @@ use Ziadoz\AssertableHtml\Dom\AssertableElement; use Ziadoz\AssertableHtml\Dom\AssertableElementsList; use Ziadoz\AssertableHtml\Dom\AssertableText; -use Ziadoz\AssertableHtml\Dom\Elements\AssertableForm; class AssertableHtmlTest extends TestCase { From bcadc9c9effefd74606b223bebcf12a7879b6e6d Mon Sep 17 00:00:00 2001 From: Jamie York Date: Wed, 25 Jun 2025 18:23:54 +0100 Subject: [PATCH 08/15] assert method wip --- src/Dom/Elements/AssertableForm.php | 82 ++++++++++++++++++++++++ tests/Integration/AssertableFormTest.php | 33 ++++++---- 2 files changed, 102 insertions(+), 13 deletions(-) diff --git a/src/Dom/Elements/AssertableForm.php b/src/Dom/Elements/AssertableForm.php index eb6148f..d1d1c1d 100644 --- a/src/Dom/Elements/AssertableForm.php +++ b/src/Dom/Elements/AssertableForm.php @@ -6,13 +6,95 @@ use Dom\Element; use Dom\HTMLElement; +use PHPUnit\Framework\Assert as PHPUnit; use Ziadoz\AssertableHtml\Contracts\PromotableAssertableElement; use Ziadoz\AssertableHtml\Dom\AssertableElement; readonly class AssertableForm extends AssertableElement implements PromotableAssertableElement { + /* + |-------------------------------------------------------------------------- + | Interface + |-------------------------------------------------------------------------- + */ + + /** {@inheritDoc} */ public static function shouldPromote(Element|HTMLElement $element): bool { return $element->tagName === 'FORM'; } + + /* + |-------------------------------------------------------------------------- + | Assert Method + |-------------------------------------------------------------------------- + */ + + /** Assert the form has the given method attribute (GET or POST). */ + public function assertMethod(string $method, ?string $message = null): static + { + $method = $this->formatMethod($method); + + $this->isValidMethod($method); + + $this->assertAttribute( + 'method', + fn (?string $value): bool => trim(mb_strtolower((string) $value)) === $method, + $message ?? sprintf( + "The form method doesn't equal [%s].", + $method, + ), + ); + + return $this; + } + + /** Assert the form has the given hidden input method (PUT, PATCH or DELETE). */ + public function assertHiddenInputMethod(string $selector, string $method, ?string $message = null): static + { + $method = $this->formatMethod($method); + + $this->isValidHiddenInputMethod($method); + + $this->querySelector($selector) + ->assertMatchesSelector('input[type="hidden"]') + ->assertAttribute( + 'value', + fn (?string $value): bool => trim(mb_strtolower((string) $value)) === $method, + $message ?? sprintf( + "The form hidden input method doesn't equal [%s].", + $method, + ), + ); + + return $this; + } + + /* + |-------------------------------------------------------------------------- + | Internal + |-------------------------------------------------------------------------- + */ + + /** Lowercase and trim the given method. */ + protected function formatMethod(string $method): string + { + return trim(mb_strtolower($method)); + } + + /** Fail if the method isn't a valid form method. */ + protected function isValidMethod(string $method): void + { + if (! in_array($this->formatMethod($method), ['get', 'post', 'dialog'])) { + PHPUnit::fail(sprintf("The method [%s] isn't a valid form method.", $method)); + } + } + + /** Fail if the method isn't a valid hidden input method. */ + protected function isValidHiddenInputMethod(string $method): void + { + if (! in_array($this->formatMethod($method), ['put', 'patch', 'delete'])) { + PHPUnit::fail(sprintf("The method [%s] isn't a valid form method.", $method)); + } + } } diff --git a/tests/Integration/AssertableFormTest.php b/tests/Integration/AssertableFormTest.php index dc81841..ed7bd80 100644 --- a/tests/Integration/AssertableFormTest.php +++ b/tests/Integration/AssertableFormTest.php @@ -6,24 +6,31 @@ use PHPUnit\Framework\TestCase; use Ziadoz\AssertableHtml\Dom\AssertableDocument; -use Ziadoz\AssertableHtml\Dom\Elements\AssertableForm; class AssertableFormTest extends TestCase { public function test_assertable_form(): void { - $this->markTestSkipped('@todo'); + // Form Methods + AssertableDocument::createFromString('
    ', LIBXML_HTML_NOIMPLIED) + ->querySelector('form') + ->assertMethod('get'); - $html = AssertableDocument::createFromString(<<<'HTML' -
    - - - -
    - HTML, LIBXML_HTML_NOIMPLIED); - - $html->one('form', function (AssertableForm $form) { - $form->dump(); - }); + AssertableDocument::createFromString('
    ', LIBXML_HTML_NOIMPLIED) + ->querySelector('form') + ->assertHiddenInputMethod('input[name="_method"]', 'put'); } + + //
    + // + // + // + // + // + // + // + // + // + //
    + } From b16531eea18c9df63abf7f7755b706862c3596f5 Mon Sep 17 00:00:00 2001 From: Jamie York Date: Wed, 25 Jun 2025 18:51:11 +0100 Subject: [PATCH 09/15] drop format helper --- src/Dom/Elements/AssertableForm.php | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/Dom/Elements/AssertableForm.php b/src/Dom/Elements/AssertableForm.php index d1d1c1d..fd9c6d2 100644 --- a/src/Dom/Elements/AssertableForm.php +++ b/src/Dom/Elements/AssertableForm.php @@ -33,7 +33,7 @@ public static function shouldPromote(Element|HTMLElement $element): bool /** Assert the form has the given method attribute (GET or POST). */ public function assertMethod(string $method, ?string $message = null): static { - $method = $this->formatMethod($method); + $method = trim(mb_strtolower($method)); $this->isValidMethod($method); @@ -52,7 +52,7 @@ public function assertMethod(string $method, ?string $message = null): static /** Assert the form has the given hidden input method (PUT, PATCH or DELETE). */ public function assertHiddenInputMethod(string $selector, string $method, ?string $message = null): static { - $method = $this->formatMethod($method); + $method = trim(mb_strtolower($method)); $this->isValidHiddenInputMethod($method); @@ -76,12 +76,6 @@ public function assertHiddenInputMethod(string $selector, string $method, ?strin |-------------------------------------------------------------------------- */ - /** Lowercase and trim the given method. */ - protected function formatMethod(string $method): string - { - return trim(mb_strtolower($method)); - } - /** Fail if the method isn't a valid form method. */ protected function isValidMethod(string $method): void { @@ -93,7 +87,7 @@ protected function isValidMethod(string $method): void /** Fail if the method isn't a valid hidden input method. */ protected function isValidHiddenInputMethod(string $method): void { - if (! in_array($this->formatMethod($method), ['put', 'patch', 'delete'])) { + if (! in_array($method, ['put', 'patch', 'delete'])) { PHPUnit::fail(sprintf("The method [%s] isn't a valid form method.", $method)); } } From 59c80c4bd9326ddf341fe5f4fc14db71588d15e8 Mon Sep 17 00:00:00 2001 From: Jamie York Date: Sun, 27 Jul 2025 16:22:34 +0100 Subject: [PATCH 10/15] asserts many --- src/Concerns/AssertsMany.php | 22 +++++ src/Dom/Elements/AssertableForm.php | 98 ++++++++++++------- tests/Integration/AssertableFormTest.php | 29 +++++- .../Unit/Concerns/Asserts/AssertsManyTest.php | 34 +++++++ 4 files changed, 146 insertions(+), 37 deletions(-) create mode 100644 src/Concerns/AssertsMany.php create mode 100644 tests/Unit/Concerns/Asserts/AssertsManyTest.php diff --git a/src/Concerns/AssertsMany.php b/src/Concerns/AssertsMany.php new file mode 100644 index 0000000..9e436da --- /dev/null +++ b/src/Concerns/AssertsMany.php @@ -0,0 +1,22 @@ +call($this); + } catch (AssertionFailedError $assertion) { + throw new AssertionFailedError(message: $message ?? $assertion->getMessage(), previous: $assertion); + } + + return $this; + } +} diff --git a/src/Dom/Elements/AssertableForm.php b/src/Dom/Elements/AssertableForm.php index fd9c6d2..f26cd42 100644 --- a/src/Dom/Elements/AssertableForm.php +++ b/src/Dom/Elements/AssertableForm.php @@ -6,12 +6,14 @@ use Dom\Element; use Dom\HTMLElement; -use PHPUnit\Framework\Assert as PHPUnit; +use Ziadoz\AssertableHtml\Concerns\AssertsMany; use Ziadoz\AssertableHtml\Contracts\PromotableAssertableElement; use Ziadoz\AssertableHtml\Dom\AssertableElement; readonly class AssertableForm extends AssertableElement implements PromotableAssertableElement { + use AssertsMany; + /* |-------------------------------------------------------------------------- | Interface @@ -30,65 +32,95 @@ public static function shouldPromote(Element|HTMLElement $element): bool |-------------------------------------------------------------------------- */ - /** Assert the form has the given method attribute (GET or POST). */ + /** Assert the form has the given method attribute. */ public function assertMethod(string $method, ?string $message = null): static { $method = trim(mb_strtolower($method)); - $this->isValidMethod($method); - $this->assertAttribute( 'method', fn (?string $value): bool => trim(mb_strtolower((string) $value)) === $method, - $message ?? sprintf( - "The form method doesn't equal [%s].", - $method, - ), + $message ?? sprintf("The form method doesn't equal [%s].", $method), ); return $this; } - /** Assert the form has the given hidden input method (PUT, PATCH or DELETE). */ - public function assertHiddenInputMethod(string $selector, string $method, ?string $message = null): static + public function assertMethodGet(?string $message = null): static { - $method = trim(mb_strtolower($method)); + $this->assertMethod('get', $message); - $this->isValidHiddenInputMethod($method); + return $this; + } - $this->querySelector($selector) - ->assertMatchesSelector('input[type="hidden"]') - ->assertAttribute( - 'value', - fn (?string $value): bool => trim(mb_strtolower((string) $value)) === $method, - $message ?? sprintf( - "The form hidden input method doesn't equal [%s].", - $method, - ), - ); + public function assertMethodPost(?string $message = null): static + { + $this->assertMethod('post', $message); + + return $this; + } + + public function assertMethodDialog(?string $message = null): static + { + $this->assertMethod('dialog', $message); return $this; } /* |-------------------------------------------------------------------------- - | Internal + | Assert Hidden Method |-------------------------------------------------------------------------- */ - /** Fail if the method isn't a valid form method. */ - protected function isValidMethod(string $method): void + /** Assert the form has the given hidden input method. */ + public function assertHiddenInputMethod(string $selector, string $method, ?string $message = null): static + { + $this->assertMany(function () use ($selector, $method): void { + $method = trim(mb_strtolower($method)); + + $this->querySelector($selector) + ->assertMatchesSelector('input[type="hidden"]') + ->assertAttribute('value', fn (?string $value): bool => trim(mb_strtolower((string) $value)) === $method); + }, $message ?? sprintf("The form hidden input method doesn't equal [%s].", $method)); + + return $this; + } + + public function assertMethodPut(?string $message = null): static { - if (! in_array($this->formatMethod($method), ['get', 'post', 'dialog'])) { - PHPUnit::fail(sprintf("The method [%s] isn't a valid form method.", $method)); - } + $this->assertHiddenInputMethod('input[type="hidden"][name="_method"]', 'put', $message); + + return $this; + } + + public function assertMethodPatch(?string $message = null): static + { + $this->assertHiddenInputMethod('input[type="hidden"][name="_method"]', 'patch', $message); + + return $this; } - /** Fail if the method isn't a valid hidden input method. */ - protected function isValidHiddenInputMethod(string $method): void + public function assertMethodDelete(?string $message = null): static { - if (! in_array($method, ['put', 'patch', 'delete'])) { - PHPUnit::fail(sprintf("The method [%s] isn't a valid form method.", $method)); - } + $this->assertHiddenInputMethod('input[type="hidden"][name="_method"]', 'delete', $message); + + return $this; + } + + /* + |-------------------------------------------------------------------------- + | Assert Upload + |-------------------------------------------------------------------------- + */ + + public function assertAcceptsUpload(?string $message = null): static + { + $this->assertMany(function (): void { + $this->assertAttribute('enctype', fn (?string $value): bool => trim(mb_strtolower((string) $value)) === 'multipart/form-data') + ->assertElementsCountGreaterThanOrEqual('input[type="file"]', 1); + }, $message ?? "The form doesn't accept uploads."); + + return $this; } } diff --git a/tests/Integration/AssertableFormTest.php b/tests/Integration/AssertableFormTest.php index ed7bd80..f1b36b6 100644 --- a/tests/Integration/AssertableFormTest.php +++ b/tests/Integration/AssertableFormTest.php @@ -12,13 +12,34 @@ class AssertableFormTest extends TestCase public function test_assertable_form(): void { // Form Methods - AssertableDocument::createFromString('
    ', LIBXML_HTML_NOIMPLIED) + AssertableDocument::createFromString('
    ', LIBXML_HTML_NOIMPLIED) ->querySelector('form') - ->assertMethod('get'); + ->assertMethodGet(); - AssertableDocument::createFromString('
    ', LIBXML_HTML_NOIMPLIED) + AssertableDocument::createFromString('
    ', LIBXML_HTML_NOIMPLIED) ->querySelector('form') - ->assertHiddenInputMethod('input[name="_method"]', 'put'); + ->assertMethodPost(); + + AssertableDocument::createFromString('
    ', LIBXML_HTML_NOIMPLIED) + ->querySelector('form') + ->assertMethodDialog(); + + AssertableDocument::createFromString('
    ', LIBXML_HTML_NOIMPLIED) + ->querySelector('form') + ->assertMethodPut(); + + AssertableDocument::createFromString('
    ', LIBXML_HTML_NOIMPLIED) + ->querySelector('form') + ->assertMethodPatch(); + + AssertableDocument::createFromString('
    ', LIBXML_HTML_NOIMPLIED) + ->querySelector('form') + ->assertMethodDelete(); + + // Form Uploads + AssertableDocument::createFromString('
    ', LIBXML_HTML_NOIMPLIED) + ->querySelector('form') + ->assertAcceptsUpload(); } //
    diff --git a/tests/Unit/Concerns/Asserts/AssertsManyTest.php b/tests/Unit/Concerns/Asserts/AssertsManyTest.php new file mode 100644 index 0000000..f4845de --- /dev/null +++ b/tests/Unit/Concerns/Asserts/AssertsManyTest.php @@ -0,0 +1,34 @@ +getAssertsMany(); + $object->assertMany(function () { + PHPUnit::assertSame('Foo', 'Bar', 'Foo is not Bar'); + }, 'The test assertion failed'); + } catch (AssertionFailedError $exception) { + $this->assertSame('The test assertion failed', $exception->getMessage()); + $this->assertSame('Foo is not Bar' . "\n" . 'Failed asserting that two strings are identical.', $exception->getPrevious()->getMessage()); + } + } + + private function getAssertsMany(): object + { + return new class + { + use AssertsMany; + }; + } +} From e28f717c7fb2ff4315f0f0ab8a4a579baf9e0103 Mon Sep 17 00:00:00 2001 From: Jamie York Date: Sun, 27 Jul 2025 16:29:43 +0100 Subject: [PATCH 11/15] docs --- src/Dom/Elements/AssertableForm.php | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Dom/Elements/AssertableForm.php b/src/Dom/Elements/AssertableForm.php index f26cd42..982f5fc 100644 --- a/src/Dom/Elements/AssertableForm.php +++ b/src/Dom/Elements/AssertableForm.php @@ -46,6 +46,7 @@ public function assertMethod(string $method, ?string $message = null): static return $this; } + /** Assert the form has the GET method attribute. */ public function assertMethodGet(?string $message = null): static { $this->assertMethod('get', $message); @@ -53,6 +54,7 @@ public function assertMethodGet(?string $message = null): static return $this; } + /** Assert the form has the POST method attribute. */ public function assertMethodPost(?string $message = null): static { $this->assertMethod('post', $message); @@ -60,6 +62,7 @@ public function assertMethodPost(?string $message = null): static return $this; } + /** Assert the form has the DIALOG method attribute. */ public function assertMethodDialog(?string $message = null): static { $this->assertMethod('dialog', $message); @@ -87,6 +90,7 @@ public function assertHiddenInputMethod(string $selector, string $method, ?strin return $this; } + /** Assert the form has the PUT hidden input method. */ public function assertMethodPut(?string $message = null): static { $this->assertHiddenInputMethod('input[type="hidden"][name="_method"]', 'put', $message); @@ -94,6 +98,7 @@ public function assertMethodPut(?string $message = null): static return $this; } + /** Assert the form has the PATCH hidden input method. */ public function assertMethodPatch(?string $message = null): static { $this->assertHiddenInputMethod('input[type="hidden"][name="_method"]', 'patch', $message); @@ -101,6 +106,7 @@ public function assertMethodPatch(?string $message = null): static return $this; } + /** Assert the form has the DELETE hidden input method. */ public function assertMethodDelete(?string $message = null): static { $this->assertHiddenInputMethod('input[type="hidden"][name="_method"]', 'delete', $message); @@ -114,6 +120,7 @@ public function assertMethodDelete(?string $message = null): static |-------------------------------------------------------------------------- */ + /** Assert the form accepts uploads (has correct enctype and at least one file input. */ public function assertAcceptsUpload(?string $message = null): static { $this->assertMany(function (): void { From b09b0beb3473dd4128e462ecff9d224ebf52c3fd Mon Sep 17 00:00:00 2001 From: Jamie York Date: Sun, 27 Jul 2025 16:32:17 +0100 Subject: [PATCH 12/15] promoter fallback --- src/Dom/AssertableElementPromoter.php | 5 ++--- tests/Unit/Dom/AssertableElementPromoterTest.php | 2 ++ 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Dom/AssertableElementPromoter.php b/src/Dom/AssertableElementPromoter.php index df22c5f..5b3290b 100644 --- a/src/Dom/AssertableElementPromoter.php +++ b/src/Dom/AssertableElementPromoter.php @@ -6,7 +6,6 @@ use Dom\Element; use Dom\HTMLElement; -use Ziadoz\AssertableHtml\Contracts\PromotableAssertableElement; use Ziadoz\AssertableHtml\Dom\Elements\AssertableForm; final readonly class AssertableElementPromoter @@ -21,13 +20,13 @@ public function __construct(private HTMLElement|Element $element) } /** Promote and return the first matching assertable element that matches the given HTML element. */ - public function promote(): (PromotableAssertableElement&AssertableElement)|null + public function promote(): AssertableElement { $match = array_find( self::CUSTOM_ELEMENTS, fn (string $customElement): bool => $customElement::shouldPromote($this->element), ); - return $match ? new $match($this->element) : null; + return $match ? new $match($this->element) : new AssertableElement($this->element); } } diff --git a/tests/Unit/Dom/AssertableElementPromoterTest.php b/tests/Unit/Dom/AssertableElementPromoterTest.php index 806f03f..94c9429 100644 --- a/tests/Unit/Dom/AssertableElementPromoterTest.php +++ b/tests/Unit/Dom/AssertableElementPromoterTest.php @@ -9,6 +9,7 @@ use Dom\HTMLElement; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; +use Ziadoz\AssertableHtml\Dom\AssertableElement; use Ziadoz\AssertableHtml\Dom\AssertableElementPromoter; use Ziadoz\AssertableHtml\Dom\Elements\AssertableForm; @@ -23,6 +24,7 @@ public function test_promote(string $html, string $class): void public static function promote_data_provider(): iterable { yield 'form' => ['', AssertableForm::class]; + yield 'fallback' => ['', AssertableElement::class]; } /* From 5254ae8f9bc1f6f54d11617e9170580408542c18 Mon Sep 17 00:00:00 2001 From: Jamie York Date: Sun, 27 Jul 2025 16:32:58 +0100 Subject: [PATCH 13/15] clean up --- tests/Integration/AssertableFormTest.php | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/tests/Integration/AssertableFormTest.php b/tests/Integration/AssertableFormTest.php index f1b36b6..0c48ca6 100644 --- a/tests/Integration/AssertableFormTest.php +++ b/tests/Integration/AssertableFormTest.php @@ -41,17 +41,4 @@ public function test_assertable_form(): void ->querySelector('form') ->assertAcceptsUpload(); } - - //
    - // - // - // - // - // - // - // - // - // - //
    - } From 9e55e5d1d8b237a3d086156d3dc0ae61c560bdf9 Mon Sep 17 00:00:00 2001 From: Jamie York Date: Sun, 27 Jul 2025 16:34:03 +0100 Subject: [PATCH 14/15] Revert "promoter fallback" This reverts commit b09b0beb3473dd4128e462ecff9d224ebf52c3fd. --- src/Dom/AssertableElementPromoter.php | 5 +++-- tests/Unit/Dom/AssertableElementPromoterTest.php | 2 -- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Dom/AssertableElementPromoter.php b/src/Dom/AssertableElementPromoter.php index 5b3290b..df22c5f 100644 --- a/src/Dom/AssertableElementPromoter.php +++ b/src/Dom/AssertableElementPromoter.php @@ -6,6 +6,7 @@ use Dom\Element; use Dom\HTMLElement; +use Ziadoz\AssertableHtml\Contracts\PromotableAssertableElement; use Ziadoz\AssertableHtml\Dom\Elements\AssertableForm; final readonly class AssertableElementPromoter @@ -20,13 +21,13 @@ public function __construct(private HTMLElement|Element $element) } /** Promote and return the first matching assertable element that matches the given HTML element. */ - public function promote(): AssertableElement + public function promote(): (PromotableAssertableElement&AssertableElement)|null { $match = array_find( self::CUSTOM_ELEMENTS, fn (string $customElement): bool => $customElement::shouldPromote($this->element), ); - return $match ? new $match($this->element) : new AssertableElement($this->element); + return $match ? new $match($this->element) : null; } } diff --git a/tests/Unit/Dom/AssertableElementPromoterTest.php b/tests/Unit/Dom/AssertableElementPromoterTest.php index 94c9429..806f03f 100644 --- a/tests/Unit/Dom/AssertableElementPromoterTest.php +++ b/tests/Unit/Dom/AssertableElementPromoterTest.php @@ -9,7 +9,6 @@ use Dom\HTMLElement; use PHPUnit\Framework\Attributes\DataProvider; use PHPUnit\Framework\TestCase; -use Ziadoz\AssertableHtml\Dom\AssertableElement; use Ziadoz\AssertableHtml\Dom\AssertableElementPromoter; use Ziadoz\AssertableHtml\Dom\Elements\AssertableForm; @@ -24,7 +23,6 @@ public function test_promote(string $html, string $class): void public static function promote_data_provider(): iterable { yield 'form' => ['
    ', AssertableForm::class]; - yield 'fallback' => ['', AssertableElement::class]; } /* From 383c8384a841b0e366387e36fc428e37d6a909dc Mon Sep 17 00:00:00 2001 From: Jamie York Date: Sun, 27 Jul 2025 16:36:10 +0100 Subject: [PATCH 15/15] proper fallback test --- tests/Unit/Dom/AssertableElementPromoterTest.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/tests/Unit/Dom/AssertableElementPromoterTest.php b/tests/Unit/Dom/AssertableElementPromoterTest.php index 806f03f..5ff943d 100644 --- a/tests/Unit/Dom/AssertableElementPromoterTest.php +++ b/tests/Unit/Dom/AssertableElementPromoterTest.php @@ -15,14 +15,21 @@ class AssertableElementPromoterTest extends TestCase { #[DataProvider('promote_data_provider')] - public function test_promote(string $html, string $class): void + public function test_promote(string $html, ?string $class = null): void { - $this->assertInstanceOf($class, new AssertableElementPromoter($this->getElement($html))->promote()); + $promoted = new AssertableElementPromoter($this->getElement($html))->promote(); + + if (is_string($class)) { + $this->assertInstanceOf($class, $promoted); + } else { + $this->assertNull($promoted); + } } public static function promote_data_provider(): iterable { yield 'form' => ['
    ', AssertableForm::class]; + yield 'null' => ['', null]; } /*