symfonytestingphpunitsymfony-panther

Why doesn't the "assertSelectorExists()" assertion show the failure message that I specify?


I'm trying to show a custom message (the URL being tested) when a PHPUnit 9.5.11 test fails. in my Symfony 4.4 app.

The class is simple:

class BaseTestCase extends PantherTestCase

In my test, I've:

$client = static::createPantherClient();
$crawler = $client->request('GET', $url);
$this->assertSelectorExists('.some-class', $url); // <- this should display the tested $url, since the second argument is supposed to be the message to show on failure

But when the test fails, all I get is:

  1. App\Tests\PropertyListingTest::testListingWithFullQueryString with data set #0 ('') Facebook\WebDriver\Exception\NoSuchElementException: no such element: Unable to locate element: {"method":"css selector","selector":".some-class"} (Session info: headless chrome=97.0.4692.71)

What's going on here? If I run this:

$this->assertEquals("a", "b", "!!!!TEST FAILED!!!!");

It works as expected:

!!!!TEST FAILED!!!! Failed asserting that two strings are equal. --- Expected +++ Actual @@ @@ -'a' +'b'


Solution

  • That behaviour actually looks like a bug to me.

    Because if you look at what assertSelectorExists does internally (see below)...

    public static function assertSelectorExists(string $selector, string $message = ''): void
    {
        $client = self::getClient();
    
        if ($client instanceof PantherClient) {
            $element = self::findElement($selector); // NoSuchElementException is thrown here
            self::assertNotNull($element, $message); // so the message is never used
            
            return;
        }
    
        self::assertNotEmpty($client->getCrawler()->filter($selector));
    }
    

    ...you'll notice that it expects findElement to return null in case if no element was found. But the problem is that findElement doesn't return null in that case, it throws an exception instead.

    To fix this, I would make my own version of assertSelectorExists like this:

    $client = static::createPantherClient();
    $crawler = $client->request('GET', $url);
    $this->assertSelectorExistsSafe($client, '.some-class', $url);
    
    protected function assertSelectorExistsSafe($client, $selector, $message)
    {
        try {
            $element = $client->findElement($client->createWebDriverByFromLocator($selector));
        } catch (\Facebook\WebDriver\Exception\NoSuchElementException $e) {
            $element = null;
        }
        self::assertNotNull($element, $message);
    }