Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wait until javascript is executed #13

Closed
woodsbox opened this issue Apr 26, 2018 · 11 comments
Closed

Wait until javascript is executed #13

woodsbox opened this issue Apr 26, 2018 · 11 comments

Comments

@woodsbox
Copy link

$page->navigate('some - url')->waitForNavigation();
$content = $page->evaluate('document.documentElement.innerHTML')->getReturnValue();

Not all javascript is executed when doing the getReturnValue.
Is there a way to wait until it's done?

@woodsbox
Copy link
Author

This problem occurs with asynchronous javascripts.

@orditeck
Copy link

@gsouf Is there any way right now to force the browser to wait until JavaScript is executed before marking waitForNavigation as completed?

@gsouf
Copy link
Member

gsouf commented Jun 13, 2018

Hi @orditeck

Do you mean, when the javascript initially executes when page has loaded?

@orditeck
Copy link

Basically I'd like the browser to wait for async call before marking waitForNavigation as done. I have a react app calling an API and during the API call it shows a loading. getReturnValue() only shows the loader, never the content, and it's all local for now so it load very fast, the browser just doesn't wait and as soon as the DOM is ready it sends the response and mark waitForNavigation as completed.

@gsouf
Copy link
Member

gsouf commented Jun 13, 2018

@orditeck there are some confusions that I need to clarify before I give you the right answer.

waitForNavigation is used when the page initially loads and getReturnValue() is used after we injected code to be executed in the browser.

Can you, please, give me a sample of the code that you are running to make sure I'll answer it corretcly?

@orditeck
Copy link

<?php
require_once 'vendor/autoload.php';

use HeadlessChromium\BrowserFactory;
use HeadlessChromium\Page;

$browserFactory = new BrowserFactory('/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome');
$browser = $browserFactory->createBrowser();

$page = $browser
    ->createPage();

$page
    ->navigate('http://page_with_react_asyn_fecth_data')
    ->waitForNavigation(Page::DOM_CONTENT_LOADED, 10000);

$html = $page
    ->evaluate('document.documentElement.innerHTML')
    ->getReturnValue();

echo $html;

@gsouf
Copy link
Member

gsouf commented Jun 13, 2018

@orditeck I think there are 2 options.

The more accurate is that you are able to identify a state where your operation has completed. For instance the loader is not in the dom anymore. Unfortunately there are no shortcut to do that in the library yet, but it can be added.

The second option is to wait for the page event networkIdle. This event occurs after the "load" event once no network operation are running for at least 500ms. The only drawback with this approach is that if the code that connects to your API waits for more than 500ms to trigger, then it would fail, but you can still try to give it a try:

$page
    ->navigate('http://page_with_react_asyn_fecth_data')
    ->waitForNavigation('networkIdle', 10000);

Can you let me know if it solves?

@orditeck
Copy link

@gsouf I agree that being able to tell the waitForNavigation function to wait until the instance of a particular element is present on the page would be really cool. For now, the second option being to wait for the networkIdle event seems to work great. Thanks for your detailed answer!

@choval
Copy link

choval commented Oct 14, 2018

@orditeck You could also deasync the function

@gregalenic
Copy link

The ->waitForNavigation('networkIdle', 60000); solved it for me. But I still had to put in a little hack couse 500ms was not enough for my JS to finish. So I made a server request where the endpoint took 5 secords to finish, and it gave me cca. 5500ms before the page got evaluated (before network idle was true I guess) .

Example:

Route::get('headlessChrome/fakeCall', function(){  
    sleep(5);
    return 'You got 5 seconds of network not idle!';
});

Am not too proud of this, but its a solution

Note: I put the server request to the page myself becouse the page I am accessing is mine. But as its possible to add a script before waitForNavigation(), technically you should be able to inject a script that makes a call to a "delay" endpoint. DID NOT TEST THIS!

If I missed an obvious solution to this problem, please ping me about it :).

@stale
Copy link

stale bot commented Jan 19, 2021

This issue has been automatically marked as stale because there has been no recent activity. It will be closed after 30 days if no further activity occurs. Thank you for your contributions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

5 participants