diff --git a/src/Asserts/BaseAssert.php b/src/Asserts/BaseAssert.php index 96cba2a..3f41ce6 100644 --- a/src/Asserts/BaseAssert.php +++ b/src/Asserts/BaseAssert.php @@ -8,6 +8,7 @@ use Sinnbeck\DomAssertions\Asserts\Traits\CanGatherAttributes; use Sinnbeck\DomAssertions\Asserts\Traits\Debugging; use Sinnbeck\DomAssertions\Asserts\Traits\InteractsWithParser; +use Sinnbeck\DomAssertions\Asserts\Traits\TrackSelectors; use Sinnbeck\DomAssertions\Asserts\Traits\UsesElementAsserts; use Sinnbeck\DomAssertions\Support\DomParser; @@ -22,6 +23,7 @@ abstract class BaseAssert use Macroable { __call as protected callMacro; } + use TrackSelectors; use UsesElementAsserts; protected array $attributes = []; diff --git a/src/Asserts/Traits/TrackSelectors.php b/src/Asserts/Traits/TrackSelectors.php new file mode 100644 index 0000000..9c8e31d --- /dev/null +++ b/src/Asserts/Traits/TrackSelectors.php @@ -0,0 +1,24 @@ +selectorPath = array_merge($previousSelectors, [$currentSelector]); + + return $this; + } + + public function getSelectors(): string + { + if (empty($this->selectorPath)) { + return '(root)'; + } + + return implode(' > ', $this->selectorPath); + } +} diff --git a/src/Asserts/Traits/UsesElementAsserts.php b/src/Asserts/Traits/UsesElementAsserts.php index ff2779b..f5af7e6 100644 --- a/src/Asserts/Traits/UsesElementAsserts.php +++ b/src/Asserts/Traits/UsesElementAsserts.php @@ -29,7 +29,7 @@ public function has(string $attribute, mixed $value = null): self $value, $found = $this->getAttribute($attribute) ), - sprintf('Could not find an attribute "%s" with value "%s". "%s" found', $attribute, $value, trim($found)) + sprintf('Could not find an attribute "%s" with value "%s". "%s" found within: %s', $attribute, $value, trim($found), $this->getSelectors()) ); return $this; @@ -52,7 +52,7 @@ public function doesntHave(string $attribute, mixed $value = null): self $value, $this->getAttribute($attribute) ), - sprintf('Found an attribute "%s" with value "%s"', $attribute, $value) + sprintf('Found an attribute "%s" with value "%s" within: %s', $attribute, $value, $this->getSelectors()) ); return $this; @@ -67,6 +67,9 @@ public function find(string $selector, $callback = null): self if (! is_null($callback)) { $elementAssert = new AssertElement($this->getContent(), $element); + + $elementAssert->withSelectors($this->selectorPath, $selector); + $callback($elementAssert); } @@ -93,7 +96,7 @@ public function contains(string $selector, $attributes = null, $count = 0): self { Assert::assertNotNull( $this->getParser()->query($selector), - sprintf('Could not find any matching element of type "%s"', $selector) + sprintf('Could not find any matching element of type "%s" within: %s', $selector, $this->getSelectors()) ); if (is_numeric($attributes)) { @@ -109,7 +112,7 @@ public function contains(string $selector, $attributes = null, $count = 0): self Assert::assertEquals( $count, $found = $this->getParser()->queryAll($selector)->count(), - sprintf('Expected to find %s elements but found %s for %s', $count, $found, $selector) + sprintf('Expected to find %s elements but found %s for %s within: %s', $count, $found, $selector, $this->getSelectors()) ); return $this; @@ -123,7 +126,7 @@ public function contains(string $selector, $attributes = null, $count = 0): self $found = collect($this->attributes[$selector]) ->filter(fn ($foundAttributes) => $this->compareAttributesArrays($attributes, $foundAttributes)) ->count(), - sprintf('Expected to find %s elements but found %s for %s', $count, $found, $selector) + sprintf('Expected to find %s elements but found %s for %s within: %s', $count, $found, $selector, $this->getSelectors()) ); } @@ -132,7 +135,7 @@ public function contains(string $selector, $attributes = null, $count = 0): self Assert::assertNotFalse( $first, - sprintf('Could not find a matching "%s" with data: %s', $selector, json_encode($attributes, JSON_PRETTY_PRINT)) + sprintf('Could not find a matching "%s" with data: %s within: %s', $selector, json_encode($attributes, JSON_PRETTY_PRINT), $this->getSelectors()) ); return $this; @@ -157,7 +160,7 @@ public function doesntContain(string $elementName, array $attributes = []): self Assert::assertFalse( $first, - sprintf('Found a matching "%s" with data: %s', $elementName, json_encode($attributes, JSON_PRETTY_PRINT)) + sprintf('Found a matching "%s" with data: %s within: %s', $elementName, json_encode($attributes, JSON_PRETTY_PRINT), $this->getSelectors()) ); return $this; @@ -175,7 +178,7 @@ public function containsText(string $needle, bool $ignoreCase = false): self [PHPUnit::class, $assertFunction], $needle, $text, - sprintf('Could not find text content "%s" containing %s', $text, $needle) + sprintf('Could not find text content "%s" containing %s within: %s', $text, $needle, $this->getSelectors()) ); return $this; @@ -193,7 +196,7 @@ public function doesntContainText(string $needle, bool $ignoreCase = false): sel [PHPUnit::class, $assertFunction], $needle, $text, - sprintf('Found text content "%s" containing %s', $text, $needle) + sprintf('Found text content "%s" containing %s within: %s', $text, $needle, $this->getSelectors()) ); return $this; @@ -204,7 +207,7 @@ public function is(string $type): self PHPUnit::assertEquals( $type, $this->getParser()->getType(), - sprintf('Element is not of type "%s"', $type) + sprintf('Element is not of type "%s" within: %s', $type, $this->getSelectors()) ); return $this; diff --git a/tests/DomTest.php b/tests/DomTest.php index 9d8bc41..5f17984 100644 --- a/tests/DomTest.php +++ b/tests/DomTest.php @@ -410,6 +410,30 @@ }); }); +it('includes dom selectors when nesting and errors occur', function () { + $this->get('nesting') + ->assertElementExists(function (AssertElement $element) { + $element->findDiv(function (AssertElement $element) { + $element->is('div'); + $element->find('div', function (AssertElement $element) { + $element->is('div'); + $element->findDiv(function (AssertElement $element) { + $element->contains('not-existing'); + }); + }); + }); + }); +})->throws(AssertionFailedError::class, 'Could not find any matching element of type "not-existing" within: div > div > div'); + +it('includes dom selectors when only one deep', function () { + $this->get('nesting') + ->assertElementExists(function (AssertElement $element) { + $element->find('.foobar', function (AssertElement $element) { + $element->is('not-real'); + }); + }); +})->throws(AssertionFailedError::class, 'Element is not of type "not-real" within: .foobar'); + it('can run the example from the readme', function () { $this->get(route('about')) ->assertOk()