symfony / panther

A browser testing and web crawling library for PHP and Symfony
MIT License
2.94k stars 222 forks source link

element is not attached to the page document #209

Open nouaman1996 opened 5 years ago

nouaman1996 commented 5 years ago

Hi, I'm trying to select a html class using $crawler->filter('.right') but its keeps returning me this error "element is not attached to the page document", this is quite strange because the class is visible in the page. I tryed to do a waitfor('.right') but not working too. Thanks

kcassam commented 5 years ago

I suggest you give more information for somebody to reproduce the problem : url and an extract of you code or a unit test

gmanen commented 5 years ago

Hey,

I just had a similar issue. In my case, the element I was waiting for was added in the DOM via Vue.js and $client->waitFor() threw a NotSuchElementException with the message you posted.

I found out that the waitFor() method throws an exception if the element you're waiting for is not in the DOM at the time you call it. It only checks for visibility of an existing element.

I was able to get the expected behaviour with this custom function:

function waitForDomElement(Client $client, string $cssSelector)
{
    $client->wait()->until(
        static function (WebDriver $driver) use ($cssSelector) {
            try {
                return $driver->findElement(WebDriverBy::cssSelector($cssSelector));
            } catch (StaleElementReferenceException $e) {
                return null;
            } catch (NoSuchElementException $e) {
                return null;
            }
        }
    );
}
renishv8 commented 5 years ago

Thanks for this function, it works pretty great, better than the native waitFor(). But like @nouaman1996, sometimes i get the error element is not attached to the page document. I took a screenshot of the page, the element is well displayed (as far i can see).

This case appears after ajax call. By example, i have a search form with auto completion. I try to test the result. So i write "Paris" in the input, the form send a php request to my db and should answer "Paris" in the dom. It works when i do it by myself of course.

The test looks like :

$client = static::createPantherClient();
$crawler->filter('.places form')->form(['query' => 'Paris']);
$client->waitFor('.city-result');
$this->assertContains('Paris', $crawler->filter('.city-result')->text());

The weirdest is that works !!!! But not everytime. Sometimes, maybe 80% of times test fails. It's better when i set a custom time to the waitFor() function

$client->waitFor('.city-result', 30, 750);

With that conf test works arround 60% of time. I tried the function of @gmanen waitForDomElement() (thanks for it), so now it works 80% of time but it's still not a complete success.

I tried to refresh the crawler by

$client->refreshCrawler();

It was helpfull many times but not for this case. I'm still investigating !

coreation commented 2 years ago

As someone who is very new to playing around with Panther, specifically for testing dynamic content, refreshCrawler() was a good tip, thanks @renishv8 !

pierre-H commented 9 months ago

Does someone have other tip ? I have the same problem ...