Skip to content
2 changes: 2 additions & 0 deletions src/Asserts/BaseAssert.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -22,6 +23,7 @@ abstract class BaseAssert
use Macroable {
__call as protected callMacro;
}
use TrackSelectors;
use UsesElementAsserts;

protected array $attributes = [];
Expand Down
24 changes: 24 additions & 0 deletions src/Asserts/Traits/TrackSelectors.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

namespace Sinnbeck\DomAssertions\Asserts\Traits;

trait TrackSelectors
{
protected array $selectorPath = [];

public function withSelectors(array $previousSelectors, string $currentSelector): self
{
$this->selectorPath = array_merge($previousSelectors, [$currentSelector]);

return $this;
}

public function getSelectors(): string
{
if (empty($this->selectorPath)) {
return '(root)';
}

return implode(' > ', $this->selectorPath);
}
}
23 changes: 13 additions & 10 deletions src/Asserts/Traits/UsesElementAsserts.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand All @@ -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);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This basically tells it to use the current closures selectors, and track the new selector. Seemed the most simple this way, but feel free to change :)

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Seems all good :)


$callback($elementAssert);
}

Expand All @@ -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)) {
Expand All @@ -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;
Expand All @@ -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())
);
}

Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
Expand Down
24 changes: 24 additions & 0 deletions tests/DomTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
Loading