diff --git a/README.md b/README.md index 1fbb635..9ce0a32 100644 --- a/README.md +++ b/README.md @@ -192,6 +192,15 @@ $this->get('/some-route') }); ``` + +For simple and quick checks, you can use `assertContainsElement`. +This method allows you to verify that a specific element exists on the page you can optionally include an array of expected attributes. +``` +$this->get('/some-route') + ->assertContainsElement('#content') + ->assertContainsElement('div.banner', ['text' => 'Successfully deleted', 'data-status' => 'success']); +``` + ### Testing forms Testing forms allows using all the dom asserts from above, but has a few special helpers to help test for forms. Instead of using `->assertElementExists()` you can use `->assertFormExists()`, or the alias `assertForm()` on the test response. diff --git a/ide-helper.php b/ide-helper.php index 71ad6ea..1594b95 100644 --- a/ide-helper.php +++ b/ide-helper.php @@ -32,6 +32,12 @@ public function assertFormExists($selector = 'form', $callback = null) /** @var \Illuminate\Testing\TestResponse $instance */ return $instance; } + + public function assertContainsElement($selector, array $attributes = []) + { + /** @var \Illuminate\Testing\TestResponse $instance */ + return $instance; + } } class TestView @@ -65,6 +71,12 @@ public function assertFormExists($selector = 'form', $callback = null) /** @var \Illuminate\Testing\TestResponse $instance */ return $instance; } + + public function assertContainsElement($selector, array $attributes = []) + { + /** @var \Illuminate\Testing\TestResponse $instance */ + return $instance; + } } class TestComponent @@ -98,5 +110,11 @@ public function assertFormExists($selector = 'form', $callback = null) /** @var \Illuminate\Testing\TestResponse $instance */ return $instance; } + + public function assertContainsElement($selector, array $attributes = []) + { + /** @var \Illuminate\Testing\TestComponent $instance */ + return $instance; + } } } diff --git a/src/TestComponentMacros.php b/src/TestComponentMacros.php index 8197b9b..2ff04ab 100644 --- a/src/TestComponentMacros.php +++ b/src/TestComponentMacros.php @@ -5,6 +5,7 @@ namespace Sinnbeck\DomAssertions; use Closure; +use DOMElement; use DOMException; use Illuminate\Testing\TestComponent; use PHPUnit\Framework\Assert; @@ -85,6 +86,74 @@ public function assertElementExists(): Closure }; } + public function assertContainsElement(): Closure + { + return function (string $selector, array $attributes = []): TestComponent { + /** @var TestComponent $this */ + Assert::assertNotEmpty( + (string) $this, + 'The component is empty!' + ); + + try { + $parser = DomParser::new((string) $this); + } catch (DOMException $exception) { + Assert::fail($exception->getMessage()); + } + + $element = $parser->query($selector); + + Assert::assertNotNull( + $element, + sprintf('No element found with selector: %s', $selector) + ); + + if (! $element instanceof DOMElement) { + Assert::fail('The element found is not a DOMElement!'); + } + + foreach ($attributes as $attribute => $expected) { + switch ($attribute) { + case 'text': + $actual = trim($element->textContent); + Assert::assertStringContainsString( + $expected, + $actual, + sprintf( + 'Failed asserting that element [%s] text contains "%s". Actual: "%s".', + $selector, + $expected, + $actual + ) + ); + break; + + default: + $actual = $element->getAttribute($attribute); + Assert::assertNotEmpty( + $actual, + sprintf('Attribute [%s] not found in element [%s].', $attribute, $selector) + ); + + Assert::assertStringContainsString( + $expected, + $actual, + sprintf( + 'Failed asserting that attribute [%s] of element [%s] contains "%s". Actual: "%s".', + $attribute, + $selector, + $expected, + $actual + ) + ); + break; + } + } + + return $this; + }; + } + public function assertForm(): Closure { return $this->assertFormExists(); diff --git a/src/TestResponseMacros.php b/src/TestResponseMacros.php index 2b4938b..7ab39b9 100644 --- a/src/TestResponseMacros.php +++ b/src/TestResponseMacros.php @@ -5,6 +5,7 @@ namespace Sinnbeck\DomAssertions; use Closure; +use DOMElement; use DOMException; use Illuminate\Testing\TestResponse; use PHPUnit\Framework\Assert; @@ -85,6 +86,74 @@ public function assertElementExists(): Closure }; } + public function assertContainsElement(): Closure + { + return function (string $selector, array $attributes = []): TestResponse { + /** @var TestResponse $this */ + Assert::assertNotEmpty( + (string) $this->getContent(), + 'The response is empty!' + ); + + try { + $parser = DomParser::new($this->getContent()); + } catch (DOMException $exception) { + Assert::fail($exception->getMessage()); + } + + $element = $parser->query($selector); + + Assert::assertNotNull( + $element, + sprintf('No element found with selector: %s', $selector) + ); + + if (! $element instanceof DOMElement) { + Assert::fail('The element found is not a DOMElement!'); + } + + foreach ($attributes as $attribute => $expected) { + switch ($attribute) { + case 'text': + $actual = trim($element->textContent); + Assert::assertStringContainsString( + $expected, + $actual, + sprintf( + 'Failed asserting that element [%s] text contains "%s". Actual: "%s".', + $selector, + $expected, + $actual + ) + ); + break; + + default: + $actual = $element->getAttribute($attribute); + Assert::assertNotEmpty( + $actual, + sprintf('Attribute [%s] not found in element [%s].', $attribute, $selector) + ); + + Assert::assertStringContainsString( + $expected, + $actual, + sprintf( + 'Failed asserting that attribute [%s] of element [%s] contains "%s". Actual: "%s".', + $attribute, + $selector, + $expected, + $actual + ) + ); + break; + } + } + + return $this; + }; + } + public function assertForm(): Closure { return $this->assertFormExists(); diff --git a/src/TestViewMacros.php b/src/TestViewMacros.php index 7092fd1..ae55f8a 100644 --- a/src/TestViewMacros.php +++ b/src/TestViewMacros.php @@ -5,6 +5,7 @@ namespace Sinnbeck\DomAssertions; use Closure; +use DOMElement; use DOMException; use Illuminate\Testing\TestView; use PHPUnit\Framework\Assert; @@ -85,6 +86,75 @@ public function assertElementExists(): Closure }; } + public function assertContainsElement(): Closure + { + return function (string $selector, array $attributes = []): TestView { + /** @var TestView $this */ + Assert::assertNotEmpty( + (string) $this, + 'The view is empty!' + ); + + try { + $parser = DomParser::new((string) $this); + } catch (DOMException $exception) { + Assert::fail($exception->getMessage()); + } + + $element = $parser->query($selector); + + Assert::assertNotNull( + $element, + sprintf('No element found with selector: %s', $selector) + ); + + if (! $element instanceof DOMElement) { + Assert::fail('The element found is not a DOMElement!'); + } + + foreach ($attributes as $attribute => $expected) { + switch ($attribute) { + case 'text': + $actual = trim($element->textContent); + Assert::assertStringContainsString( + $expected, + $actual, + sprintf( + 'Failed asserting that element [%s] text contains "%s". Actual: "%s".', + $selector, + $expected, + $actual + ) + ); + break; + + default: + $actual = $element->getAttribute($attribute); + + Assert::assertNotEmpty( + $actual, + sprintf('Attribute [%s] not found in element [%s].', $attribute, $selector) + ); + + Assert::assertStringContainsString( + $expected, + $actual, + sprintf( + 'Failed asserting that attribute [%s] of element [%s] contains "%s". Actual: "%s".', + $attribute, + $selector, + $expected, + $actual + ) + ); + break; + } + } + + return $this; + }; + } + public function assertForm(): Closure { return $this->assertFormExists(); diff --git a/tests/ComponentTest.php b/tests/ComponentTest.php index a0c04c1..af54800 100644 --- a/tests/ComponentTest.php +++ b/tests/ComponentTest.php @@ -23,6 +23,27 @@ }); }); +it('assertContainsElement works as expects', function () { + $this->component(NestedComponent::class) + ->assertContainsElement('span.foo', ['text' => 'Foo', 'class' => 'bar foo']) + ->assertContainsElement('nav'); +}); + +it('assertContainsElement throws if selector not found', function () { + $this->component(NestedComponent::class) + ->assertContainsElement('span.non-existing', ['text' => 'Foo']); +})->throws(AssertionFailedError::class, 'No element found with selector: span.non-existing'); + +it('assertContainsElement throws if contains text does not exist', function () { + $this->component(NestedComponent::class) + ->assertContainsElement('span.foo', ['text' => 'non-existing']); +})->throws(AssertionFailedError::class, 'Failed asserting that element [span.foo] text contains "non-existing". Actual: "Foo"'); + +it('assertContainsElement throws if contains attribute does not exist', function () { + $this->view('nesting') + ->assertContainsElement('span.foo', ['non-existing-attribute' => 'non-existing']); +})->throws(AssertionFailedError::class, 'Attribute [non-existing-attribute] not found in element [span.foo]'); + it('can handle an empty component', function () { $this->component(EmptyComponent::class) ->assertElementExists(); diff --git a/tests/DomTest.php b/tests/DomTest.php index 1705de6..3eceb3f 100644 --- a/tests/DomTest.php +++ b/tests/DomTest.php @@ -10,6 +10,27 @@ }); }); +it('assertContainsElement works as expects', function () { + $this->get('nesting') + ->assertContainsElement('span.foo', ['text' => 'Foo', 'class' => 'bar foo']) + ->assertContainsElement('nav'); +}); + +it('assertContainsElement throws if selector not found', function () { + $this->get('nesting') + ->assertContainsElement('span.non-existing', ['text' => 'Foo']); +})->throws(AssertionFailedError::class, 'No element found with selector: span.non-existing'); + +it('assertContainsElement throws if contains text does not exist', function () { + $this->get('nesting') + ->assertContainsElement('span.foo', ['text' => 'non-existing']); +})->throws(AssertionFailedError::class, 'Failed asserting that element [span.foo] text contains "non-existing". Actual: "Foo"'); + +it('assertContainsElement throws if contains attribute does not exist', function () { + $this->view('nesting') + ->assertContainsElement('span.foo', ['non-existing-attribute' => 'non-existing']); +})->throws(AssertionFailedError::class, 'Attribute [non-existing-attribute] not found in element [span.foo]'); + it('can handle an empty view', function () { $this->get('empty') ->assertElementExists(); diff --git a/tests/ViewTest.php b/tests/ViewTest.php index 5478da6..eb1906a 100644 --- a/tests/ViewTest.php +++ b/tests/ViewTest.php @@ -3,6 +3,27 @@ use PHPUnit\Framework\AssertionFailedError; use Sinnbeck\DomAssertions\Asserts\AssertElement; +it('assertContainsElement works as expects', function () { + $this->view('nesting') + ->assertContainsElement('span.foo', ['text' => 'Foo']) + ->assertContainsElement('nav'); +}); + +it('assertContainsElement throws if selector not found', function () { + $this->view('nesting') + ->assertContainsElement('span.non-existing', ['text' => 'Foo']); +})->throws(AssertionFailedError::class, 'No element found with selector: span.non-existing'); + +it('assertContainsElement throws if contains text does not exist', function () { + $this->view('nesting') + ->assertContainsElement('span.foo', ['text' => 'non-existing']); +})->throws(AssertionFailedError::class, 'Failed asserting that element [span.foo] text contains "non-existing". Actual: "Foo"'); + +it('assertContainsElement throws if contains attribute does not exist', function () { + $this->view('nesting') + ->assertContainsElement('span.foo', ['non-existing-attribute' => 'non-existing']); +})->throws(AssertionFailedError::class, 'Attribute [non-existing-attribute] not found in element [span.foo]'); + it('assertElement alias works for assertElementExists', function () { $this->view('nesting') ->assertElement('body', function (AssertElement $assert) { diff --git a/tests/views/components/NestedComponent.php b/tests/views/components/NestedComponent.php index 2d2fef1..02b3f19 100644 --- a/tests/views/components/NestedComponent.php +++ b/tests/views/components/NestedComponent.php @@ -12,7 +12,25 @@ public function render(): string { return <<<'HTML'
-
+ +
+ Foo +
+
+
+ +
+
+
    +
  • +
  • +
+
+

+ Foo + Bar +

+
HTML; }